ajax-datatables-rails 0.4.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|