ajax-datatables-rails 1.2.0 → 1.3.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/.github/workflows/ci.yml +120 -0
- data/.rubocop.yml +3 -1
- data/Appraisals +7 -13
- data/CHANGELOG.md +23 -2
- data/README.md +51 -70
- data/ajax-datatables-rails.gemspec +11 -5
- data/doc/migrate.md +44 -0
- data/doc/webpack.md +4 -1
- data/gemfiles/{rails_5.2.3.gemfile → rails_5.2.4.gemfile} +1 -1
- data/gemfiles/{rails_6.0.1.gemfile → rails_6.0.3.gemfile} +1 -1
- data/gemfiles/{rails_5.0.7.gemfile → rails_6.1.0.gemfile} +3 -3
- data/lib/ajax-datatables-rails.rb +0 -16
- data/lib/ajax-datatables-rails/base.rb +38 -13
- data/lib/ajax-datatables-rails/datatable.rb +6 -0
- data/lib/ajax-datatables-rails/datatable/column.rb +59 -21
- data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +1 -1
- data/lib/ajax-datatables-rails/datatable/column/search.rb +2 -2
- data/lib/ajax-datatables-rails/datatable/datatable.rb +17 -3
- data/lib/ajax-datatables-rails/datatable/simple_order.rb +7 -5
- 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 +9 -10
- data/lib/ajax-datatables-rails/version.rb +1 -1
- data/spec/ajax-datatables-rails/base_spec.rb +77 -120
- data/spec/ajax-datatables-rails/datatable/column_spec.rb +30 -10
- data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +61 -22
- data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +11 -9
- data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +352 -257
- data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +4 -4
- data/spec/install_oracle.sh +4 -4
- data/spec/spec_helper.rb +10 -19
- data/spec/support/datatables/complex_datatable.rb +29 -0
- data/spec/support/datatables/complex_datatable_array.rb +14 -0
- data/spec/support/{datatable_cond_date.rb → datatables/datatable_cond_date.rb} +0 -0
- data/spec/support/{datatable_cond_numeric.rb → datatables/datatable_cond_numeric.rb} +0 -0
- data/spec/support/{datatable_cond_proc.rb → datatables/datatable_cond_proc.rb} +0 -0
- data/spec/support/{datatable_cond_string.rb → datatables/datatable_cond_string.rb} +0 -0
- data/spec/support/datatables/datatable_cond_unknown.rb +5 -0
- data/spec/support/{datatable_order_nulls_last.rb → datatables/datatable_order_nulls_last.rb} +0 -0
- data/spec/support/{test_helpers.rb → helpers/params.rb} +8 -46
- data/spec/support/{test_models.rb → models/user.rb} +0 -0
- metadata +53 -49
- data/.travis.yml +0 -57
- data/gemfiles/rails_5.1.7.gemfile +0 -11
- data/lib/ajax-datatables-rails/configuration.rb +0 -10
- data/lib/generators/datatable/config_generator.rb +0 -19
- data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -9
- data/spec/ajax-datatables-rails/configuration_spec.rb +0 -34
- data/spec/ajax-datatables-rails/extended_spec.rb +0 -19
data/doc/migrate.md
CHANGED
@@ -1,5 +1,35 @@
|
|
1
|
+
## To migrate from `v1.0.x` to `v1.3.0`
|
2
|
+
|
3
|
+
The *v1.3.0* version has some breaking changes :
|
4
|
+
|
5
|
+
* `AjaxDatatablesRails.config.db_adapter=` is removed and is configured per datatable class now. It defaults to Rails DB adapter. (fixes [#364](https://github.com/jbox-web/ajax-datatables-rails/issues/364))
|
6
|
+
|
7
|
+
This change is transparent for everyone. Just remove `AjaxDatatablesRails.config.db_adapter=` from your configuration (if exists) and it should work fine.
|
8
|
+
|
9
|
+
Now you can use AjaxDatatablesRails in multi-db environments.
|
10
|
+
|
11
|
+
* `AjaxDatatablesRails.config.nulls_last=` is removed and is configured per datatable class now (or by column). It defaults to false.
|
12
|
+
|
13
|
+
This change is easy to mitigate : add `self.nulls_last = true` in [`ApplicationDatatable`](https://github.com/jbox-web/ajax-datatables-rails#create-a-master-parent-class-easy) and remove `AjaxDatatablesRails.config.nulls_last=`
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
class ApplicationDatatable < AjaxDatatablesRails::ActiveRecord
|
17
|
+
self.nulls_last = true
|
18
|
+
# puts commonly used methods here
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
* `AjaxDatatablesRails.config` is removed with no replacement
|
23
|
+
|
24
|
+
Fix the two changes above and remove any configuration file about AjaxDatatablesRails. The gem is now configless :)
|
25
|
+
|
1
26
|
## To migrate from `v0.4.x` to `v1.0.0`
|
2
27
|
|
28
|
+
The *v1.0.0* version is a **major break** from *v0.4*.
|
29
|
+
|
30
|
+
* Datatables no longer inherits from `AjaxDatatablesRails::Base` but from `AjaxDatatablesRails::ActiveRecord` (this solves [#228](https://github.com/jbox-web/ajax-datatables-rails/issues/228))
|
31
|
+
* The `view_context` is no longer injected in Datatables but only the `params` hash (see the [example](#4-setup-the-controller-action)). This will break calls to helpers methods.
|
32
|
+
|
3
33
|
1) To mitigate the first change (Datatables no longer inherits from `AjaxDatatablesRails::Base` but from `AjaxDatatablesRails::ActiveRecord`)
|
4
34
|
|
5
35
|
Create a new `ApplicationDatatable` class and make all your classes inherits from it :
|
@@ -51,3 +81,17 @@ end
|
|
51
81
|
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
82
|
|
53
83
|
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).
|
84
|
+
|
85
|
+
## To migrate from `v0.3.x` to `v0.4.x`
|
86
|
+
|
87
|
+
The *v0.4* version is a **major break** from *v0.3*.
|
88
|
+
|
89
|
+
The core has been rewriten to remove dependency on [Kaminari](https://github.com/kaminari/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate).
|
90
|
+
|
91
|
+
It also brings a new (more natural) way of defining columns, based on hash definitions (and not arrays) and add some filtering options for column search.
|
92
|
+
|
93
|
+
To migrate on the v0.4 you'll need to :
|
94
|
+
|
95
|
+
* update your DataTables classes to remove all the `extend` directives
|
96
|
+
* switch to hash definitions of `view_columns`
|
97
|
+
* update your views to declare your columns bindings ([See here](https://github.com/jbox-web/ajax-datatables-rails#5-wire-up-the-javascript))
|
data/doc/webpack.md
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "rails", "
|
6
|
-
gem "activerecord-oracle_enhanced-adapter", "~> 1.
|
7
|
-
gem "sqlite3", "~> 1.
|
5
|
+
gem "rails", "6.1.0"
|
6
|
+
gem "activerecord-oracle_enhanced-adapter", "~> 6.1.0"
|
7
|
+
gem "sqlite3", "~> 1.4.0"
|
8
8
|
gem "mysql2"
|
9
9
|
gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
|
10
10
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_support/configurable'
|
4
|
-
|
5
3
|
require 'zeitwerk'
|
6
4
|
loader = Zeitwerk::Loader.for_gem
|
7
5
|
generators = "#{__dir__}/generators"
|
@@ -13,18 +11,4 @@ loader.inflector.inflect(
|
|
13
11
|
loader.setup
|
14
12
|
|
15
13
|
module AjaxDatatablesRails
|
16
|
-
# Configure AjaxDatatablesRails global settings
|
17
|
-
#
|
18
|
-
# AjaxDatatablesRails.configure do |config|
|
19
|
-
# config.db_adapter = :postgresql
|
20
|
-
# end
|
21
|
-
|
22
|
-
def self.configure
|
23
|
-
yield @config ||= AjaxDatatablesRails::Configuration.new
|
24
|
-
end
|
25
|
-
|
26
|
-
# AjaxDatatablesRails global settings
|
27
|
-
def self.config
|
28
|
-
@config ||= AjaxDatatablesRails::Configuration.new
|
29
|
-
end
|
30
14
|
end
|
@@ -3,6 +3,9 @@
|
|
3
3
|
module AjaxDatatablesRails
|
4
4
|
class Base
|
5
5
|
|
6
|
+
class_attribute :db_adapter, default: ActiveRecord::Base.connection.adapter_name.downcase.to_sym
|
7
|
+
class_attribute :nulls_last, default: false
|
8
|
+
|
6
9
|
attr_reader :params, :options, :datatable
|
7
10
|
|
8
11
|
GLOBAL_SEARCH_DELIMITER = ' '
|
@@ -13,6 +16,7 @@ module AjaxDatatablesRails
|
|
13
16
|
@datatable = Datatable::Datatable.new(self)
|
14
17
|
end
|
15
18
|
|
19
|
+
# User defined methods
|
16
20
|
def view_columns
|
17
21
|
raise(NotImplementedError, view_columns_error_text)
|
18
22
|
end
|
@@ -25,10 +29,29 @@ module AjaxDatatablesRails
|
|
25
29
|
raise(NotImplementedError, data_error_text)
|
26
30
|
end
|
27
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
|
28
50
|
def additional_data
|
29
51
|
{}
|
30
52
|
end
|
31
53
|
|
54
|
+
# JSON structure sent to jQuery DataTables
|
32
55
|
def as_json(*)
|
33
56
|
{
|
34
57
|
recordsTotal: records_total_count,
|
@@ -37,10 +60,18 @@ module AjaxDatatablesRails
|
|
37
60
|
}.merge(additional_data)
|
38
61
|
end
|
39
62
|
|
40
|
-
|
41
|
-
|
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')
|
42
71
|
end
|
43
72
|
|
73
|
+
private
|
74
|
+
|
44
75
|
# helper methods
|
45
76
|
def connected_columns
|
46
77
|
@connected_columns ||= begin
|
@@ -62,8 +93,6 @@ module AjaxDatatablesRails
|
|
62
93
|
end
|
63
94
|
end
|
64
95
|
|
65
|
-
private
|
66
|
-
|
67
96
|
def sanitize_data(data)
|
68
97
|
data.map do |record|
|
69
98
|
if record.is_a?(Array)
|
@@ -74,6 +103,11 @@ module AjaxDatatablesRails
|
|
74
103
|
end
|
75
104
|
end
|
76
105
|
|
106
|
+
# called from within #data
|
107
|
+
def records
|
108
|
+
@records ||= retrieve_records
|
109
|
+
end
|
110
|
+
|
77
111
|
def retrieve_records
|
78
112
|
records = fetch_records
|
79
113
|
records = filter_records(records)
|
@@ -94,15 +128,6 @@ module AjaxDatatablesRails
|
|
94
128
|
GLOBAL_SEARCH_DELIMITER
|
95
129
|
end
|
96
130
|
|
97
|
-
def column_id(name)
|
98
|
-
view_columns.keys.index(name.to_sym)
|
99
|
-
end
|
100
|
-
|
101
|
-
def column_data(column)
|
102
|
-
id = column_id(column)
|
103
|
-
params.dig('columns', id.to_s, 'search', 'value')
|
104
|
-
end
|
105
|
-
|
106
131
|
def raw_records_error_text
|
107
132
|
<<-ERROR
|
108
133
|
|
@@ -4,35 +4,23 @@ 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
|
-
TYPE_CAST_SQLSERVER = 'VARCHAR(4000)'
|
12
|
-
|
13
|
-
DB_ADAPTER_TYPE_CAST = {
|
14
|
-
mysql: TYPE_CAST_MYSQL,
|
15
|
-
mysql2: TYPE_CAST_MYSQL,
|
16
|
-
sqlite: TYPE_CAST_SQLITE,
|
17
|
-
sqlite3: TYPE_CAST_SQLITE,
|
18
|
-
oracle: TYPE_CAST_ORACLE,
|
19
|
-
oracleenhanced: TYPE_CAST_ORACLE,
|
20
|
-
sqlserver: TYPE_CAST_SQLSERVER,
|
21
|
-
}.freeze
|
22
|
-
|
23
|
-
attr_reader :datatable, :index, :options
|
24
|
-
attr_writer :search
|
25
|
-
|
26
7
|
include Search
|
27
8
|
include Order
|
28
9
|
include DateFilter
|
29
10
|
|
11
|
+
attr_reader :datatable, :index, :options
|
12
|
+
attr_writer :search
|
30
13
|
|
31
14
|
def initialize(datatable, index, options)
|
32
15
|
@datatable = datatable
|
33
16
|
@index = index
|
34
17
|
@options = options
|
35
|
-
@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
|
36
24
|
end
|
37
25
|
|
38
26
|
def data
|
@@ -71,14 +59,64 @@ module AjaxDatatablesRails
|
|
71
59
|
|
72
60
|
private
|
73
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
|
+
|
74
85
|
def type_cast
|
75
|
-
@type_cast ||= DB_ADAPTER_TYPE_CAST.fetch(
|
86
|
+
@type_cast ||= DB_ADAPTER_TYPE_CAST.fetch(datatable.db_adapter, TYPE_CAST_DEFAULT)
|
76
87
|
end
|
77
88
|
|
78
89
|
def casted_column
|
79
90
|
@casted_column ||= ::Arel::Nodes::NamedFunction.new('CAST', [table[field].as(type_cast)])
|
80
91
|
end
|
81
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
|
+
|
82
120
|
end
|
83
121
|
end
|
84
122
|
end
|
@@ -55,7 +55,7 @@ module AjaxDatatablesRails
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def range_end_casted
|
58
|
-
range_end.blank? ?
|
58
|
+
range_end.blank? ? parse_date('9999-12-31 23:59:59') : parse_date("#{range_end} 23:59:59")
|
59
59
|
end
|
60
60
|
|
61
61
|
def parse_date(date)
|
@@ -61,8 +61,6 @@ module AjaxDatatablesRails
|
|
61
61
|
filter
|
62
62
|
when :eq, :not_eq, :lt, :gt, :lteq, :gteq, :in
|
63
63
|
searchable_integer? ? raw_search(cond) : empty_search
|
64
|
-
when :null_value
|
65
|
-
null_value_search
|
66
64
|
when :start_with
|
67
65
|
casted_column.matches("#{formatted_value}%")
|
68
66
|
when :end_with
|
@@ -73,6 +71,8 @@ module AjaxDatatablesRails
|
|
73
71
|
raw_search(:eq)
|
74
72
|
when :string_in
|
75
73
|
raw_search(:in)
|
74
|
+
when :null_value
|
75
|
+
null_value_search
|
76
76
|
when :date_range
|
77
77
|
date_range_search
|
78
78
|
end
|
@@ -4,7 +4,7 @@ module AjaxDatatablesRails
|
|
4
4
|
module Datatable
|
5
5
|
|
6
6
|
class Datatable
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :options
|
8
8
|
|
9
9
|
def initialize(datatable)
|
10
10
|
@datatable = datatable
|
@@ -41,7 +41,7 @@ module AjaxDatatablesRails
|
|
41
41
|
|
42
42
|
def columns
|
43
43
|
@columns ||= get_param(:columns).map do |index, column_options|
|
44
|
-
Column.new(datatable, index, column_options)
|
44
|
+
Column.new(@datatable, index, column_options)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -70,7 +70,21 @@ module AjaxDatatablesRails
|
|
70
70
|
def get_param(param)
|
71
71
|
return {} if options[param].nil?
|
72
72
|
|
73
|
-
options[param].
|
73
|
+
if options[param].is_a? Array
|
74
|
+
hash = {}
|
75
|
+
options[param].each_with_index { |value, index| hash[index] = value }
|
76
|
+
hash
|
77
|
+
else
|
78
|
+
options[param].to_unsafe_h.with_indifferent_access
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def db_adapter
|
83
|
+
@datatable.db_adapter
|
84
|
+
end
|
85
|
+
|
86
|
+
def nulls_last
|
87
|
+
@datatable.nulls_last
|
74
88
|
end
|
75
89
|
|
76
90
|
end
|
@@ -9,8 +9,10 @@ module AjaxDatatablesRails
|
|
9
9
|
DIRECTIONS = [DIRECTION_ASC, DIRECTION_DESC].freeze
|
10
10
|
|
11
11
|
def initialize(datatable, options = {})
|
12
|
-
@datatable
|
13
|
-
@options
|
12
|
+
@datatable = datatable
|
13
|
+
@options = options
|
14
|
+
@adapter = datatable.db_adapter
|
15
|
+
@nulls_last = datatable.nulls_last
|
14
16
|
end
|
15
17
|
|
16
18
|
def query(sort_column)
|
@@ -36,19 +38,19 @@ module AjaxDatatablesRails
|
|
36
38
|
end
|
37
39
|
|
38
40
|
def sort_nulls_last?
|
39
|
-
column.nulls_last? ||
|
41
|
+
column.nulls_last? || @nulls_last == true
|
40
42
|
end
|
41
43
|
|
42
44
|
def nulls_last_sql
|
43
45
|
return unless sort_nulls_last?
|
44
46
|
|
45
|
-
case
|
47
|
+
case @adapter
|
46
48
|
when :pg, :postgresql, :postgres, :oracle
|
47
49
|
'NULLS LAST'
|
48
50
|
when :mysql, :mysql2, :sqlite, :sqlite3
|
49
51
|
'IS NULL'
|
50
52
|
else
|
51
|
-
raise
|
53
|
+
raise "unsupported database adapter: #{@adapter}"
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|