ajax-datatables-rails 0.4.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.travis.yml +6 -41
  4. data/Appraisals +0 -8
  5. data/CHANGELOG.md +8 -1
  6. data/README.md +152 -26
  7. data/ajax-datatables-rails.gemspec +3 -4
  8. data/doc/migrate.md +53 -0
  9. data/lib/ajax-datatables-rails/active_record.rb +7 -0
  10. data/lib/ajax-datatables-rails/base.rb +7 -23
  11. data/lib/ajax-datatables-rails/config.rb +3 -6
  12. data/lib/ajax-datatables-rails/datatable/column.rb +18 -13
  13. data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +10 -20
  14. data/lib/ajax-datatables-rails/datatable/column/order.rb +1 -1
  15. data/lib/ajax-datatables-rails/datatable/column/search.rb +29 -20
  16. data/lib/ajax-datatables-rails/datatable/datatable.rb +1 -7
  17. data/lib/ajax-datatables-rails/datatable/simple_order.rb +4 -2
  18. data/lib/ajax-datatables-rails/datatable/simple_search.rb +2 -0
  19. data/lib/ajax-datatables-rails/version.rb +1 -1
  20. data/lib/ajax_datatables_rails.rb +2 -1
  21. data/lib/generators/datatable/config_generator.rb +4 -4
  22. data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -3
  23. data/lib/generators/rails/templates/datatable.rb +1 -1
  24. data/spec/ajax-datatables-rails/base_spec.rb +81 -41
  25. data/spec/ajax-datatables-rails/configuration_spec.rb +0 -9
  26. data/spec/ajax-datatables-rails/datatable/column_spec.rb +58 -12
  27. data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +1 -2
  28. data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +2 -3
  29. data/spec/ajax-datatables-rails/extended_spec.rb +1 -2
  30. data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +84 -137
  31. data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +1 -2
  32. data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +4 -5
  33. data/spec/ajax-datatables-rails/orm/active_record_spec.rb +3 -4
  34. data/spec/spec_helper.rb +0 -2
  35. data/spec/support/datatable_cond_numeric.rb +1 -1
  36. data/spec/support/datatable_cond_string.rb +1 -1
  37. data/spec/support/test_helpers.rb +1 -1
  38. metadata +8 -8
  39. data/gemfiles/rails_4.0.13.gemfile +0 -14
  40. data/gemfiles/rails_4.1.16.gemfile +0 -14
@@ -0,0 +1,53 @@
1
+ ## To migrate from `v0.4.x` to `v1.0.0`
2
+
3
+ 1) To mitigate the first change (Datatables no longer inherits from `AjaxDatatablesRails::Base` but from `AjaxDatatablesRails::ActiveRecord`)
4
+
5
+ Create a new `ApplicationDatatable` class and make all your classes inherits from it :
6
+
7
+ ```ruby
8
+ class ApplicationDatatable < AjaxDatatablesRails::ActiveRecord
9
+ end
10
+
11
+ class PostDatatable < ApplicationDatatable
12
+ end
13
+ ```
14
+
15
+ **Note :** This is now in the [ProTips™](https://github.com/jbox-web/ajax-datatables-rails#protips) section of the documentation.
16
+
17
+ 2) To mitigate the second change (The `view_context` is no longer injected in Datatables)
18
+
19
+ Update the `ApplicationDatatable` class :
20
+
21
+ ```ruby
22
+ class ApplicationDatatable < AjaxDatatablesRails::ActiveRecord
23
+ extend Forwardable
24
+ attr_reader :view
25
+ def initialize(params, opts = {})
26
+ @view = opts[:view_context]
27
+ super
28
+ end
29
+ end
30
+ ```
31
+
32
+ and update your controllers :
33
+
34
+ ```ruby
35
+ # before
36
+ respond_to do |format|
37
+ format.json { render json: UserDatatable.new(view_context) }
38
+ end
39
+
40
+ # after
41
+ respond_to do |format|
42
+ format.json { render json: UserDatatable.new(params, view_context: view_context) }
43
+ end
44
+
45
+ # if you need to inject some options
46
+ respond_to do |format|
47
+ format.json { render json: UserDatatable.new(params, view_context: view_context, my: 'options') }
48
+ end
49
+ ```
50
+
51
+ This way, you can still use `def_delegators` in your datatables [as in the documentation](https://github.com/jbox-web/ajax-datatables-rails#using-view-helpers).
52
+
53
+ Note that the recommanded way is to use [Draper gem](https://github.com/drapergem/draper) to separate filtering logic from view/presentation logic [as in the documentation](https://github.com/jbox-web/ajax-datatables-rails#using-view-decorators).
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AjaxDatatablesRails
4
+ class ActiveRecord < AjaxDatatablesRails::Base
5
+ include AjaxDatatablesRails::ORM::ActiveRecord
6
+ end
7
+ end
@@ -2,21 +2,15 @@
2
2
 
3
3
  module AjaxDatatablesRails
4
4
  class Base
5
- extend Forwardable
6
5
 
7
- attr_reader :view, :options
8
- def_delegator :@view, :params
6
+ attr_reader :params, :options, :datatable
9
7
 
10
8
  GLOBAL_SEARCH_DELIMITER = ' '
11
9
 
12
- def initialize(view, options = {})
13
- @view = view
14
- @options = options
15
- load_orm_extension
16
- end
17
-
18
- def datatable
19
- @datatable ||= Datatable::Datatable.new(self)
10
+ def initialize(params, options = {})
11
+ @params = params
12
+ @options = options
13
+ @datatable = Datatable::Datatable.new(self)
20
14
  end
21
15
 
22
16
  def view_columns
@@ -37,9 +31,9 @@ module AjaxDatatablesRails
37
31
 
38
32
  def as_json(*)
39
33
  {
40
- recordsTotal: records_total_count,
34
+ recordsTotal: records_total_count,
41
35
  recordsFiltered: records_filtered_count,
42
- data: sanitize(data)
36
+ data: sanitize(data)
43
37
  }.merge(get_additional_data)
44
38
  end
45
39
 
@@ -113,16 +107,6 @@ module AjaxDatatablesRails
113
107
  filter_records(fetch_records).count(:all)
114
108
  end
115
109
 
116
- # Private helper methods
117
- def load_orm_extension
118
- case AjaxDatatablesRails.config.orm
119
- when :active_record
120
- extend ORM::ActiveRecord
121
- when :mongoid
122
- nil
123
- end
124
- end
125
-
126
110
  def global_search_delimiter
127
111
  GLOBAL_SEARCH_DELIMITER
128
112
  end
@@ -4,10 +4,12 @@ require 'active_support/configurable'
4
4
 
5
5
  module AjaxDatatablesRails
6
6
 
7
- # configure AjaxDatatablesRails global settings
7
+ # Configure AjaxDatatablesRails global settings
8
+ #
8
9
  # AjaxDatatablesRails.configure do |config|
9
10
  # config.db_adapter = :postgresql
10
11
  # end
12
+
11
13
  def self.configure
12
14
  yield @config ||= AjaxDatatablesRails::Configuration.new
13
15
  end
@@ -17,14 +19,9 @@ module AjaxDatatablesRails
17
19
  @config ||= AjaxDatatablesRails::Configuration.new
18
20
  end
19
21
 
20
- def self.old_rails?
21
- Rails::VERSION::MAJOR == 4 && (Rails::VERSION::MINOR == 1 || Rails::VERSION::MINOR == 0)
22
- end
23
-
24
22
  class Configuration
25
23
  include ActiveSupport::Configurable
26
24
 
27
- config_accessor(:orm) { :active_record }
28
25
  config_accessor(:db_adapter) { :postgresql }
29
26
  config_accessor(:nulls_last) { false }
30
27
  end
@@ -4,13 +4,18 @@ module AjaxDatatablesRails
4
4
  module Datatable
5
5
  class Column
6
6
 
7
+ TYPE_CAST_DEFAULT = 'VARCHAR'
8
+ TYPE_CAST_MYSQL = 'CHAR'
9
+ TYPE_CAST_SQLITE = 'TEXT'
10
+ TYPE_CAST_ORACLE = 'VARCHAR2(4000)'
11
+
7
12
  DB_ADAPTER_TYPE_CAST = {
8
- mysql: 'CHAR',
9
- mysql2: 'CHAR',
10
- sqlite: 'TEXT',
11
- sqlite3: 'TEXT',
12
- oracle: 'VARCHAR2(4000)',
13
- oracleenhanced: 'VARCHAR2(4000)'
13
+ mysql: TYPE_CAST_MYSQL,
14
+ mysql2: TYPE_CAST_MYSQL,
15
+ sqlite: TYPE_CAST_SQLITE,
16
+ sqlite3: TYPE_CAST_SQLITE,
17
+ oracle: TYPE_CAST_ORACLE,
18
+ oracleenhanced: TYPE_CAST_ORACLE
14
19
  }.freeze
15
20
 
16
21
  attr_reader :datatable, :index, :options
@@ -18,7 +23,7 @@ module AjaxDatatablesRails
18
23
 
19
24
  include Search
20
25
  include Order
21
- prepend DateFilter unless AjaxDatatablesRails.old_rails?
26
+ include DateFilter
22
27
 
23
28
 
24
29
  def initialize(datatable, index, options)
@@ -52,20 +57,20 @@ module AjaxDatatablesRails
52
57
  !source.include?('.')
53
58
  end
54
59
 
55
- # Add formater option to allow modification of the value
60
+ # Add formatter option to allow modification of the value
56
61
  # before passing it to the database
57
- def formater
58
- @view_column[:formater]
62
+ def formatter
63
+ @view_column[:formatter]
59
64
  end
60
65
 
61
- def formated_value
62
- formater ? formater.call(search.value) : search.value
66
+ def formatted_value
67
+ formatter ? formatter.call(search.value) : search.value
63
68
  end
64
69
 
65
70
  private
66
71
 
67
72
  def type_cast
68
- @type_cast ||= (DB_ADAPTER_TYPE_CAST[AjaxDatatablesRails.config.db_adapter] || 'VARCHAR')
73
+ @type_cast ||= DB_ADAPTER_TYPE_CAST.fetch(AjaxDatatablesRails.config.db_adapter, TYPE_CAST_DEFAULT)
69
74
  end
70
75
 
71
76
  def casted_column
@@ -5,6 +5,8 @@ module AjaxDatatablesRails
5
5
  class Column
6
6
  module DateFilter
7
7
 
8
+ RANGE_DELIMITER = '-'
9
+
8
10
  class DateRange
9
11
  attr_reader :begin, :end
10
12
 
@@ -20,23 +22,23 @@ module AjaxDatatablesRails
20
22
 
21
23
  # Add delimiter option to handle range search
22
24
  def delimiter
23
- @view_column[:delimiter] || '-'
24
- end
25
-
26
- def empty_range_search?
27
- (formated_value == delimiter) || (range_start.blank? && range_end.blank?)
25
+ @delimiter ||= @view_column.fetch(:delimiter, RANGE_DELIMITER)
28
26
  end
29
27
 
30
28
  # A range value is in form '<range_start><delimiter><range_end>'
31
29
  # This returns <range_start>
32
30
  def range_start
33
- @range_start ||= formated_value.split(delimiter)[0]
31
+ @range_start ||= formatted_value.split(delimiter)[0]
34
32
  end
35
33
 
36
34
  # A range value is in form '<range_start><delimiter><range_end>'
37
35
  # This returns <range_end>
38
36
  def range_end
39
- @range_end ||= formated_value.split(delimiter)[1]
37
+ @range_end ||= formatted_value.split(delimiter)[1]
38
+ end
39
+
40
+ def empty_range_search?
41
+ (formatted_value == delimiter) || (range_start.blank? && range_end.blank?)
40
42
  end
41
43
 
42
44
  # Do a range search
@@ -47,14 +49,6 @@ module AjaxDatatablesRails
47
49
 
48
50
  private
49
51
 
50
- def non_regex_search
51
- if cond == :date_range
52
- date_range_search
53
- else
54
- super
55
- end
56
- end
57
-
58
52
  def range_start_casted
59
53
  range_start.blank? ? parse_date('01/01/1970') : parse_date(range_start)
60
54
  end
@@ -64,11 +58,7 @@ module AjaxDatatablesRails
64
58
  end
65
59
 
66
60
  def parse_date(date)
67
- if Time.zone
68
- Time.zone.parse(date)
69
- else
70
- Time.parse(date)
71
- end
61
+ Time.zone ? Time.zone.parse(date) : Time.parse(date)
72
62
  end
73
63
 
74
64
  end
@@ -11,7 +11,7 @@ module AjaxDatatablesRails
11
11
 
12
12
  # Add sort_field option to allow overriding of sort field
13
13
  def sort_field
14
- @view_column[:sort_field] || field
14
+ @view_column.fetch(:sort_field, field)
15
15
  end
16
16
 
17
17
  def sort_query
@@ -5,19 +5,21 @@ module AjaxDatatablesRails
5
5
  class Column
6
6
  module Search
7
7
 
8
- SMALLEST_PQ_INTEGER = -2147483648
9
- LARGEST_PQ_INTEGER = 2147483647
8
+ SMALLEST_PQ_INTEGER = -2_147_483_648
9
+ LARGEST_PQ_INTEGER = 2_147_483_647
10
+ NOT_NULL_VALUE = '!NULL'
11
+ EMPTY_VALUE = ''
10
12
 
11
13
  def searchable?
12
14
  @view_column.fetch(:searchable, true)
13
15
  end
14
16
 
15
17
  def cond
16
- @view_column[:cond] || :like
18
+ @view_column.fetch(:cond, :like)
17
19
  end
18
20
 
19
21
  def filter
20
- @view_column[:cond].call(self, formated_value)
22
+ @view_column[:cond].call(self, formatted_value)
21
23
  end
22
24
 
23
25
  def search
@@ -46,33 +48,37 @@ module AjaxDatatablesRails
46
48
  # The solution is to bypass regex_search and use non_regex_search with :in operator
47
49
  def regex_search
48
50
  if use_regex?
49
- ::Arel::Nodes::Regexp.new((custom_field? ? field : table[field]), ::Arel::Nodes.build_quoted(formated_value))
51
+ ::Arel::Nodes::Regexp.new((custom_field? ? field : table[field]), ::Arel::Nodes.build_quoted(formatted_value))
50
52
  else
51
53
  non_regex_search
52
54
  end
53
55
  end
54
56
 
57
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
55
58
  def non_regex_search
56
59
  case cond
57
60
  when Proc
58
61
  filter
59
62
  when :eq, :not_eq, :lt, :gt, :lteq, :gteq, :in
60
- is_searchable_integer? ? raw_search(cond) : empty_search
63
+ searchable_integer? ? raw_search(cond) : empty_search
61
64
  when :null_value
62
65
  null_value_search
63
66
  when :start_with
64
- casted_column.matches("#{formated_value}%")
67
+ casted_column.matches("#{formatted_value}%")
65
68
  when :end_with
66
- casted_column.matches("%#{formated_value}")
69
+ casted_column.matches("%#{formatted_value}")
67
70
  when :like
68
- casted_column.matches("%#{formated_value}%")
71
+ casted_column.matches("%#{formatted_value}%")
69
72
  when :string_eq
70
73
  raw_search(:eq)
74
+ when :date_range
75
+ date_range_search
71
76
  end
72
77
  end
78
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
73
79
 
74
80
  def null_value_search
75
- if formated_value == '!NULL'
81
+ if formatted_value == NOT_NULL_VALUE
76
82
  table[field].not_eq(nil)
77
83
  else
78
84
  table[field].eq(nil)
@@ -81,31 +87,34 @@ module AjaxDatatablesRails
81
87
 
82
88
  def raw_search(cond)
83
89
  if custom_field?
84
- ::Arel::Nodes::SqlLiteral.new(field).eq(formated_value)
90
+ ::Arel::Nodes::SqlLiteral.new(field).eq(formatted_value)
85
91
  else
86
- table[field].send(cond, formated_value)
92
+ table[field].send(cond, formatted_value)
87
93
  end
88
94
  end
89
95
 
90
96
  def empty_search
91
- casted_column.matches('')
97
+ casted_column.matches(EMPTY_VALUE)
92
98
  end
93
99
 
94
- def is_searchable_integer?
95
- if formated_value.is_a?(Array)
96
- valids = formated_value.map { |v| is_integer?(v) && !is_out_of_range?(v) }
100
+ def searchable_integer?
101
+ if formatted_value.is_a?(Array)
102
+ valids = formatted_value.map { |v| integer?(v) && !out_of_range?(v) }
97
103
  !valids.include?(false)
98
104
  else
99
- is_integer?(formated_value) && !is_out_of_range?(formated_value)
105
+ integer?(formatted_value) && !out_of_range?(formatted_value)
100
106
  end
101
107
  end
102
108
 
103
- def is_out_of_range?(search_value)
109
+ def out_of_range?(search_value)
104
110
  Integer(search_value) > LARGEST_PQ_INTEGER || Integer(search_value) < SMALLEST_PQ_INTEGER
105
111
  end
106
112
 
107
- def is_integer?(string)
108
- true if Integer(string) rescue false
113
+ def integer?(string)
114
+ Integer(string)
115
+ true
116
+ rescue ArgumentError
117
+ false
109
118
  end
110
119
 
111
120
  end
@@ -3,8 +3,6 @@
3
3
  module AjaxDatatablesRails
4
4
  module Datatable
5
5
 
6
- TRUE_VALUE = 'true'
7
-
8
6
  class Datatable
9
7
  attr_reader :datatable, :options
10
8
 
@@ -70,11 +68,7 @@ module AjaxDatatablesRails
70
68
  end
71
69
 
72
70
  def get_param(param)
73
- if AjaxDatatablesRails.old_rails?
74
- options[param]
75
- else
76
- options[param].to_unsafe_h.with_indifferent_access
77
- end
71
+ options[param].to_unsafe_h.with_indifferent_access
78
72
  end
79
73
 
80
74
  end
@@ -4,7 +4,9 @@ module AjaxDatatablesRails
4
4
  module Datatable
5
5
  class SimpleOrder
6
6
 
7
- DIRECTIONS = %w[DESC ASC].freeze
7
+ DIRECTION_ASC = 'ASC'
8
+ DIRECTION_DESC = 'DESC'
9
+ DIRECTIONS = [DIRECTION_ASC, DIRECTION_DESC].freeze
8
10
 
9
11
  def initialize(datatable, options = {})
10
12
  @datatable = datatable
@@ -24,7 +26,7 @@ module AjaxDatatablesRails
24
26
  end
25
27
 
26
28
  def direction
27
- DIRECTIONS.find { |dir| dir == column_direction } || 'ASC'
29
+ DIRECTIONS.find { |dir| dir == column_direction } || DIRECTION_ASC
28
30
  end
29
31
 
30
32
  private
@@ -4,6 +4,8 @@ module AjaxDatatablesRails
4
4
  module Datatable
5
5
  class SimpleSearch
6
6
 
7
+ TRUE_VALUE = 'true'
8
+
7
9
  def initialize(options = {})
8
10
  @options = options
9
11
  end