ajax-datatables-rails 0.4.3 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +120 -0
- data/.rubocop.yml +17 -7
- data/Appraisals +15 -20
- data/CHANGELOG.md +54 -1
- data/Gemfile +0 -5
- data/Guardfile +16 -0
- data/README.md +238 -112
- data/Rakefile +1 -0
- data/ajax-datatables-rails.gemspec +24 -20
- data/bin/_guard-core +29 -0
- data/bin/appraisal +29 -0
- data/bin/bundle +114 -0
- data/bin/guard +29 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/doc/migrate.md +97 -0
- data/doc/webpack.md +7 -2
- data/gemfiles/{rails_5.2.0.gemfile → rails_5.2.4.gemfile} +3 -5
- data/gemfiles/{rails_5.0.7.gemfile → rails_6.0.3.gemfile} +4 -6
- data/gemfiles/{rails_5.1.6.gemfile → rails_6.1.0.gemfile} +4 -6
- data/lib/ajax-datatables-rails.rb +12 -1
- data/lib/ajax-datatables-rails/active_record.rb +7 -0
- data/lib/ajax-datatables-rails/base.rb +47 -46
- data/lib/ajax-datatables-rails/datatable.rb +6 -0
- data/lib/ajax-datatables-rails/datatable/column.rb +65 -20
- data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +12 -21
- data/lib/ajax-datatables-rails/datatable/column/order.rb +1 -1
- data/lib/ajax-datatables-rails/datatable/column/search.rb +37 -22
- data/lib/ajax-datatables-rails/datatable/datatable.rb +16 -7
- data/lib/ajax-datatables-rails/datatable/simple_order.rb +23 -10
- data/lib/ajax-datatables-rails/datatable/simple_search.rb +2 -0
- data/lib/ajax-datatables-rails/error.rb +9 -0
- data/lib/ajax-datatables-rails/orm.rb +6 -0
- data/lib/ajax-datatables-rails/orm/active_record.rb +11 -12
- data/lib/ajax-datatables-rails/version.rb +13 -1
- data/lib/generators/rails/templates/datatable.rb +1 -1
- data/spec/ajax-datatables-rails/base_spec.rb +129 -93
- data/spec/ajax-datatables-rails/datatable/column_spec.rb +105 -37
- data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +71 -31
- data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +36 -14
- data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +4 -2
- data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +315 -272
- data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +9 -8
- data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +17 -14
- data/spec/factories/user.rb +3 -1
- data/spec/install_oracle.sh +9 -3
- data/spec/spec_helper.rb +33 -28
- data/spec/support/datatables/complex_datatable.rb +31 -0
- data/spec/support/datatables/complex_datatable_array.rb +16 -0
- data/spec/support/{datatable_cond_date.rb → datatables/datatable_cond_date.rb} +2 -0
- data/spec/support/{datatable_cond_numeric.rb → datatables/datatable_cond_numeric.rb} +3 -1
- data/spec/support/{datatable_cond_proc.rb → datatables/datatable_cond_proc.rb} +2 -0
- data/spec/support/{datatable_cond_string.rb → datatables/datatable_cond_string.rb} +9 -1
- data/spec/support/datatables/datatable_cond_unknown.rb +7 -0
- data/spec/support/{datatable_order_nulls_last.rb → datatables/datatable_order_nulls_last.rb} +2 -0
- data/spec/support/{test_helpers.rb → helpers/params.rb} +17 -42
- data/spec/support/{test_models.rb → models/user.rb} +2 -0
- data/spec/support/schema.rb +3 -1
- metadata +76 -75
- data/.travis.yml +0 -80
- data/gemfiles/rails_4.0.13.gemfile +0 -14
- data/gemfiles/rails_4.1.16.gemfile +0 -14
- data/gemfiles/rails_4.2.10.gemfile +0 -14
- data/lib/ajax-datatables-rails/config.rb +0 -31
- data/lib/ajax_datatables_rails.rb +0 -15
- data/lib/generators/datatable/config_generator.rb +0 -19
- data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -12
- data/spec/ajax-datatables-rails/configuration_spec.rb +0 -43
- data/spec/ajax-datatables-rails/extended_spec.rb +0 -20
- data/spec/ajax-datatables-rails/orm/active_record_spec.rb +0 -25
data/doc/webpack.md
CHANGED
@@ -5,7 +5,9 @@ We assume here that Bootstrap and FontAwesome are already installed with Webpack
|
|
5
5
|
Inspired by https://datatables.net/download and completed :
|
6
6
|
|
7
7
|
Add npm packages :
|
8
|
-
|
8
|
+
```sh
|
9
|
+
$ yarn add imports-loader
|
10
|
+
```
|
9
11
|
```sh
|
10
12
|
$ yarn add datatables.net
|
11
13
|
$ yarn add datatables.net-bs
|
@@ -22,7 +24,10 @@ In `config/webpack/loaders/datatables.js` :
|
|
22
24
|
```js
|
23
25
|
module.exports = {
|
24
26
|
test: /datatables\.net.*/,
|
25
|
-
loader: 'imports-loader
|
27
|
+
loader: 'imports-loader',
|
28
|
+
options: {
|
29
|
+
additionalCode: 'var define = false;'
|
30
|
+
}
|
26
31
|
}
|
27
32
|
```
|
28
33
|
|
@@ -2,12 +2,10 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "rails", "5.2.
|
5
|
+
gem "rails", "5.2.4"
|
6
6
|
gem "activerecord-oracle_enhanced-adapter", "~> 5.2.0"
|
7
|
+
gem "sqlite3", "~> 1.3.0"
|
8
|
+
gem "mysql2"
|
7
9
|
gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
|
8
10
|
|
9
|
-
group :test do
|
10
|
-
gem "codeclimate-test-reporter", "~> 1.0.0"
|
11
|
-
end
|
12
|
-
|
13
11
|
gemspec path: "../"
|
@@ -2,12 +2,10 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "rails", "
|
6
|
-
gem "activerecord-oracle_enhanced-adapter", "~>
|
5
|
+
gem "rails", "6.0.3"
|
6
|
+
gem "activerecord-oracle_enhanced-adapter", "~> 6.0.0"
|
7
|
+
gem "sqlite3", "~> 1.4.0"
|
8
|
+
gem "mysql2"
|
7
9
|
gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
|
8
10
|
|
9
|
-
group :test do
|
10
|
-
gem "codeclimate-test-reporter", "~> 1.0.0"
|
11
|
-
end
|
12
|
-
|
13
11
|
gemspec path: "../"
|
@@ -2,12 +2,10 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "rails", "
|
6
|
-
gem "activerecord-oracle_enhanced-adapter", "~> 1.
|
5
|
+
gem "rails", "6.1.0"
|
6
|
+
gem "activerecord-oracle_enhanced-adapter", "~> 6.1.0"
|
7
|
+
gem "sqlite3", "~> 1.4.0"
|
8
|
+
gem "mysql2"
|
7
9
|
gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
|
8
10
|
|
9
|
-
group :test do
|
10
|
-
gem "codeclimate-test-reporter", "~> 1.0.0"
|
11
|
-
end
|
12
|
-
|
13
11
|
gemspec path: "../"
|
@@ -1,3 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'zeitwerk'
|
4
|
+
loader = Zeitwerk::Loader.for_gem
|
5
|
+
generators = "#{__dir__}/generators"
|
6
|
+
loader.ignore(generators)
|
7
|
+
loader.inflector.inflect(
|
8
|
+
'orm' => 'ORM',
|
9
|
+
'ajax-datatables-rails' => 'AjaxDatatablesRails'
|
10
|
+
)
|
11
|
+
loader.setup
|
12
|
+
|
13
|
+
module AjaxDatatablesRails
|
14
|
+
end
|
@@ -2,23 +2,21 @@
|
|
2
2
|
|
3
3
|
module AjaxDatatablesRails
|
4
4
|
class Base
|
5
|
-
extend Forwardable
|
6
5
|
|
7
|
-
|
8
|
-
|
6
|
+
class_attribute :db_adapter, default: ::ActiveRecord::Base.connection.adapter_name.downcase.to_sym
|
7
|
+
class_attribute :nulls_last, default: false
|
9
8
|
|
10
|
-
|
9
|
+
attr_reader :params, :options, :datatable
|
11
10
|
|
12
|
-
|
13
|
-
@view = view
|
14
|
-
@options = options
|
15
|
-
load_orm_extension
|
16
|
-
end
|
11
|
+
GLOBAL_SEARCH_DELIMITER = ' '
|
17
12
|
|
18
|
-
def
|
19
|
-
@
|
13
|
+
def initialize(params, options = {})
|
14
|
+
@params = params
|
15
|
+
@options = options
|
16
|
+
@datatable = Datatable::Datatable.new(self)
|
20
17
|
end
|
21
18
|
|
19
|
+
# User defined methods
|
22
20
|
def view_columns
|
23
21
|
raise(NotImplementedError, view_columns_error_text)
|
24
22
|
end
|
@@ -31,22 +29,49 @@ module AjaxDatatablesRails
|
|
31
29
|
raise(NotImplementedError, data_error_text)
|
32
30
|
end
|
33
31
|
|
32
|
+
# ORM defined methods
|
33
|
+
def fetch_records
|
34
|
+
get_raw_records
|
35
|
+
end
|
36
|
+
|
37
|
+
def filter_records(records)
|
38
|
+
raise(NotImplementedError)
|
39
|
+
end
|
40
|
+
|
41
|
+
def sort_records(records)
|
42
|
+
raise(NotImplementedError)
|
43
|
+
end
|
44
|
+
|
45
|
+
def paginate_records(records)
|
46
|
+
raise(NotImplementedError)
|
47
|
+
end
|
48
|
+
|
49
|
+
# User overides
|
34
50
|
def additional_data
|
35
51
|
{}
|
36
52
|
end
|
37
53
|
|
54
|
+
# JSON structure sent to jQuery DataTables
|
38
55
|
def as_json(*)
|
39
56
|
{
|
40
|
-
recordsTotal:
|
57
|
+
recordsTotal: records_total_count,
|
41
58
|
recordsFiltered: records_filtered_count,
|
42
|
-
data:
|
43
|
-
}.merge(
|
59
|
+
data: sanitize_data(data),
|
60
|
+
}.merge(additional_data)
|
44
61
|
end
|
45
62
|
|
46
|
-
|
47
|
-
|
63
|
+
# User helper methods
|
64
|
+
def column_id(name)
|
65
|
+
view_columns.keys.index(name.to_sym)
|
66
|
+
end
|
67
|
+
|
68
|
+
def column_data(column)
|
69
|
+
id = column_id(column)
|
70
|
+
params.dig('columns', id.to_s, 'search', 'value')
|
48
71
|
end
|
49
72
|
|
73
|
+
private
|
74
|
+
|
50
75
|
# helper methods
|
51
76
|
def connected_columns
|
52
77
|
@connected_columns ||= begin
|
@@ -68,26 +93,7 @@ module AjaxDatatablesRails
|
|
68
93
|
end
|
69
94
|
end
|
70
95
|
|
71
|
-
|
72
|
-
|
73
|
-
# This method is necessary for smooth transition from
|
74
|
-
# `additinonal_datas` method to `additional_data`
|
75
|
-
# without breaking change.
|
76
|
-
def get_additional_data
|
77
|
-
if respond_to?(:additional_datas)
|
78
|
-
puts <<-WARNING
|
79
|
-
`additional_datas` has been deprecated and
|
80
|
-
will be removed in next major version update!
|
81
|
-
Please use `additional_data` instead.
|
82
|
-
WARNING
|
83
|
-
|
84
|
-
additional_datas
|
85
|
-
else
|
86
|
-
additional_data
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def sanitize(data)
|
96
|
+
def sanitize_data(data)
|
91
97
|
data.map do |record|
|
92
98
|
if record.is_a?(Array)
|
93
99
|
record.map { |td| ERB::Util.html_escape(td) }
|
@@ -97,6 +103,11 @@ module AjaxDatatablesRails
|
|
97
103
|
end
|
98
104
|
end
|
99
105
|
|
106
|
+
# called from within #data
|
107
|
+
def records
|
108
|
+
@records ||= retrieve_records
|
109
|
+
end
|
110
|
+
|
100
111
|
def retrieve_records
|
101
112
|
records = fetch_records
|
102
113
|
records = filter_records(records)
|
@@ -113,16 +124,6 @@ module AjaxDatatablesRails
|
|
113
124
|
filter_records(fetch_records).count(:all)
|
114
125
|
end
|
115
126
|
|
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
127
|
def global_search_delimiter
|
127
128
|
GLOBAL_SEARCH_DELIMITER
|
128
129
|
end
|
@@ -4,28 +4,23 @@ module AjaxDatatablesRails
|
|
4
4
|
module Datatable
|
5
5
|
class Column
|
6
6
|
|
7
|
-
DB_ADAPTER_TYPE_CAST = {
|
8
|
-
mysql: 'CHAR',
|
9
|
-
mysql2: 'CHAR',
|
10
|
-
sqlite: 'TEXT',
|
11
|
-
sqlite3: 'TEXT',
|
12
|
-
oracle: 'VARCHAR2(4000)',
|
13
|
-
oracleenhanced: 'VARCHAR2(4000)'
|
14
|
-
}.freeze
|
15
|
-
|
16
|
-
attr_reader :datatable, :index, :options
|
17
|
-
attr_writer :search
|
18
|
-
|
19
7
|
include Search
|
20
8
|
include Order
|
21
|
-
|
9
|
+
include DateFilter
|
22
10
|
|
11
|
+
attr_reader :datatable, :index, :options
|
12
|
+
attr_writer :search
|
23
13
|
|
24
14
|
def initialize(datatable, index, options)
|
25
15
|
@datatable = datatable
|
26
16
|
@index = index
|
27
17
|
@options = options
|
28
|
-
@view_column = datatable.view_columns[
|
18
|
+
@view_column = datatable.view_columns[column_name]
|
19
|
+
validate_settings!
|
20
|
+
end
|
21
|
+
|
22
|
+
def column_name
|
23
|
+
@column_name ||= options[:data]&.to_sym
|
29
24
|
end
|
30
25
|
|
31
26
|
def data
|
@@ -52,26 +47,76 @@ module AjaxDatatablesRails
|
|
52
47
|
!source.include?('.')
|
53
48
|
end
|
54
49
|
|
55
|
-
# Add
|
50
|
+
# Add formatter option to allow modification of the value
|
56
51
|
# before passing it to the database
|
57
|
-
def
|
58
|
-
@view_column[:
|
52
|
+
def formatter
|
53
|
+
@view_column[:formatter]
|
59
54
|
end
|
60
55
|
|
61
|
-
def
|
62
|
-
|
56
|
+
def formatted_value
|
57
|
+
formatter ? formatter.call(search.value) : search.value
|
63
58
|
end
|
64
59
|
|
65
60
|
private
|
66
61
|
|
62
|
+
TYPE_CAST_DEFAULT = 'VARCHAR'
|
63
|
+
TYPE_CAST_MYSQL = 'CHAR'
|
64
|
+
TYPE_CAST_SQLITE = 'TEXT'
|
65
|
+
TYPE_CAST_ORACLE = 'VARCHAR2(4000)'
|
66
|
+
TYPE_CAST_SQLSERVER = 'VARCHAR(4000)'
|
67
|
+
|
68
|
+
DB_ADAPTER_TYPE_CAST = {
|
69
|
+
mysql: TYPE_CAST_MYSQL,
|
70
|
+
mysql2: TYPE_CAST_MYSQL,
|
71
|
+
sqlite: TYPE_CAST_SQLITE,
|
72
|
+
sqlite3: TYPE_CAST_SQLITE,
|
73
|
+
oracle: TYPE_CAST_ORACLE,
|
74
|
+
oracleenhanced: TYPE_CAST_ORACLE,
|
75
|
+
sqlserver: TYPE_CAST_SQLSERVER,
|
76
|
+
}.freeze
|
77
|
+
|
78
|
+
private_constant :TYPE_CAST_DEFAULT
|
79
|
+
private_constant :TYPE_CAST_MYSQL
|
80
|
+
private_constant :TYPE_CAST_SQLITE
|
81
|
+
private_constant :TYPE_CAST_ORACLE
|
82
|
+
private_constant :TYPE_CAST_SQLSERVER
|
83
|
+
private_constant :DB_ADAPTER_TYPE_CAST
|
84
|
+
|
67
85
|
def type_cast
|
68
|
-
@type_cast ||=
|
86
|
+
@type_cast ||= DB_ADAPTER_TYPE_CAST.fetch(datatable.db_adapter, TYPE_CAST_DEFAULT)
|
69
87
|
end
|
70
88
|
|
71
89
|
def casted_column
|
72
90
|
@casted_column ||= ::Arel::Nodes::NamedFunction.new('CAST', [table[field].as(type_cast)])
|
73
91
|
end
|
74
92
|
|
93
|
+
def validate_settings!
|
94
|
+
raise AjaxDatatablesRails::Error::InvalidSearchColumn, "Unknown column. Check that `data` field is filled on JS side with the column name" if column_name.empty?
|
95
|
+
raise AjaxDatatablesRails::Error::InvalidSearchColumn, "Check that column '#{column_name}' exists in view_columns" unless valid_search_column?(column_name)
|
96
|
+
raise AjaxDatatablesRails::Error::InvalidSearchCondition, cond unless valid_search_condition?(cond)
|
97
|
+
end
|
98
|
+
|
99
|
+
def valid_search_column?(column_name)
|
100
|
+
!datatable.view_columns[column_name].nil?
|
101
|
+
end
|
102
|
+
|
103
|
+
VALID_SEARCH_CONDITIONS = [
|
104
|
+
# String condition
|
105
|
+
:start_with, :end_with, :like, :string_eq, :string_in, :null_value,
|
106
|
+
# Numeric condition
|
107
|
+
:eq, :not_eq, :lt, :gt, :lteq, :gteq, :in,
|
108
|
+
# Date condition
|
109
|
+
:date_range
|
110
|
+
].freeze
|
111
|
+
|
112
|
+
private_constant :VALID_SEARCH_CONDITIONS
|
113
|
+
|
114
|
+
def valid_search_condition?(cond)
|
115
|
+
return true if cond.is_a?(Proc)
|
116
|
+
|
117
|
+
VALID_SEARCH_CONDITIONS.include?(cond)
|
118
|
+
end
|
119
|
+
|
75
120
|
end
|
76
121
|
end
|
77
122
|
end
|
@@ -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,55 +22,44 @@ 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
|
43
45
|
def date_range_search
|
44
46
|
return nil if empty_range_search?
|
47
|
+
|
45
48
|
table[field].between(DateRange.new(range_start_casted, range_end_casted))
|
46
49
|
end
|
47
50
|
|
48
51
|
private
|
49
52
|
|
50
|
-
def non_regex_search
|
51
|
-
if cond == :date_range
|
52
|
-
date_range_search
|
53
|
-
else
|
54
|
-
super
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
53
|
def range_start_casted
|
59
54
|
range_start.blank? ? parse_date('01/01/1970') : parse_date(range_start)
|
60
55
|
end
|
61
56
|
|
62
57
|
def range_end_casted
|
63
|
-
range_end.blank? ?
|
58
|
+
range_end.blank? ? parse_date('9999-12-31 23:59:59') : parse_date("#{range_end} 23:59:59")
|
64
59
|
end
|
65
60
|
|
66
61
|
def parse_date(date)
|
67
|
-
|
68
|
-
Time.zone.parse(date)
|
69
|
-
else
|
70
|
-
Time.parse(date)
|
71
|
-
end
|
62
|
+
Time.zone ? Time.zone.parse(date) : Time.parse(date)
|
72
63
|
end
|
73
64
|
|
74
65
|
end
|