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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/.travis.yml +6 -41
- data/Appraisals +0 -8
- data/CHANGELOG.md +8 -1
- data/README.md +152 -26
- data/ajax-datatables-rails.gemspec +3 -4
- data/doc/migrate.md +53 -0
- data/lib/ajax-datatables-rails/active_record.rb +7 -0
- data/lib/ajax-datatables-rails/base.rb +7 -23
- data/lib/ajax-datatables-rails/config.rb +3 -6
- data/lib/ajax-datatables-rails/datatable/column.rb +18 -13
- data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +10 -20
- data/lib/ajax-datatables-rails/datatable/column/order.rb +1 -1
- data/lib/ajax-datatables-rails/datatable/column/search.rb +29 -20
- data/lib/ajax-datatables-rails/datatable/datatable.rb +1 -7
- data/lib/ajax-datatables-rails/datatable/simple_order.rb +4 -2
- data/lib/ajax-datatables-rails/datatable/simple_search.rb +2 -0
- data/lib/ajax-datatables-rails/version.rb +1 -1
- data/lib/ajax_datatables_rails.rb +2 -1
- data/lib/generators/datatable/config_generator.rb +4 -4
- data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -3
- data/lib/generators/rails/templates/datatable.rb +1 -1
- data/spec/ajax-datatables-rails/base_spec.rb +81 -41
- data/spec/ajax-datatables-rails/configuration_spec.rb +0 -9
- data/spec/ajax-datatables-rails/datatable/column_spec.rb +58 -12
- data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +1 -2
- data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +2 -3
- data/spec/ajax-datatables-rails/extended_spec.rb +1 -2
- data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +84 -137
- data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +1 -2
- data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +4 -5
- data/spec/ajax-datatables-rails/orm/active_record_spec.rb +3 -4
- data/spec/spec_helper.rb +0 -2
- data/spec/support/datatable_cond_numeric.rb +1 -1
- data/spec/support/datatable_cond_string.rb +1 -1
- data/spec/support/test_helpers.rb +1 -1
- metadata +8 -8
- data/gemfiles/rails_4.0.13.gemfile +0 -14
- data/gemfiles/rails_4.1.16.gemfile +0 -14
data/doc/migrate.md
ADDED
@@ -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).
|
@@ -2,21 +2,15 @@
|
|
2
2
|
|
3
3
|
module AjaxDatatablesRails
|
4
4
|
class Base
|
5
|
-
extend Forwardable
|
6
5
|
|
7
|
-
attr_reader :
|
8
|
-
def_delegator :@view, :params
|
6
|
+
attr_reader :params, :options, :datatable
|
9
7
|
|
10
8
|
GLOBAL_SEARCH_DELIMITER = ' '
|
11
9
|
|
12
|
-
def initialize(
|
13
|
-
@
|
14
|
-
@options
|
15
|
-
|
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:
|
34
|
+
recordsTotal: records_total_count,
|
41
35
|
recordsFiltered: records_filtered_count,
|
42
|
-
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
|
-
#
|
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:
|
9
|
-
mysql2:
|
10
|
-
sqlite:
|
11
|
-
sqlite3:
|
12
|
-
oracle:
|
13
|
-
oracleenhanced:
|
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
|
-
|
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
|
60
|
+
# Add formatter option to allow modification of the value
|
56
61
|
# before passing it to the database
|
57
|
-
def
|
58
|
-
@view_column[:
|
62
|
+
def formatter
|
63
|
+
@view_column[:formatter]
|
59
64
|
end
|
60
65
|
|
61
|
-
def
|
62
|
-
|
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 ||= (
|
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
|
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 ||=
|
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 ||=
|
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
|
-
|
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
|
@@ -5,19 +5,21 @@ module AjaxDatatablesRails
|
|
5
5
|
class Column
|
6
6
|
module Search
|
7
7
|
|
8
|
-
SMALLEST_PQ_INTEGER = -
|
9
|
-
LARGEST_PQ_INTEGER
|
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
|
18
|
+
@view_column.fetch(:cond, :like)
|
17
19
|
end
|
18
20
|
|
19
21
|
def filter
|
20
|
-
@view_column[:cond].call(self,
|
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(
|
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
|
-
|
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("#{
|
67
|
+
casted_column.matches("#{formatted_value}%")
|
65
68
|
when :end_with
|
66
|
-
casted_column.matches("%#{
|
69
|
+
casted_column.matches("%#{formatted_value}")
|
67
70
|
when :like
|
68
|
-
casted_column.matches("%#{
|
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
|
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(
|
90
|
+
::Arel::Nodes::SqlLiteral.new(field).eq(formatted_value)
|
85
91
|
else
|
86
|
-
table[field].send(cond,
|
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
|
95
|
-
if
|
96
|
-
valids =
|
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
|
-
|
105
|
+
integer?(formatted_value) && !out_of_range?(formatted_value)
|
100
106
|
end
|
101
107
|
end
|
102
108
|
|
103
|
-
def
|
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
|
108
|
-
|
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
|
-
|
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
|
-
|
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 } ||
|
29
|
+
DIRECTIONS.find { |dir| dir == column_direction } || DIRECTION_ASC
|
28
30
|
end
|
29
31
|
|
30
32
|
private
|