ajax-datatables-rails 0.4.0 → 0.4.1
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 +5 -5
- data/.rubocop.yml +23 -1132
- data/.travis.yml +36 -24
- data/Appraisals +14 -8
- data/CHANGELOG.md +32 -7
- data/Gemfile +2 -0
- data/README.md +400 -335
- data/Rakefile +2 -1
- data/ajax-datatables-rails.gemspec +8 -6
- data/doc/webpack.md +50 -0
- data/gemfiles/{rails_4.1.15.gemfile → rails_4.1.16.gemfile} +1 -1
- data/gemfiles/{rails_4.2.8.gemfile → rails_4.2.10.gemfile} +2 -1
- data/gemfiles/{rails_5.0.3.gemfile → rails_5.0.7.gemfile} +1 -1
- data/gemfiles/{rails_5.1.1.gemfile → rails_5.1.6.gemfile} +1 -1
- data/gemfiles/rails_5.2.0.gemfile +13 -0
- data/lib/ajax-datatables-rails.rb +3 -11
- data/lib/ajax-datatables-rails/base.rb +44 -24
- data/lib/ajax-datatables-rails/config.rb +3 -0
- data/lib/ajax-datatables-rails/datatable/column.rb +33 -125
- data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +77 -0
- data/lib/ajax-datatables-rails/datatable/column/order.rb +29 -0
- data/lib/ajax-datatables-rails/datatable/column/search.rb +88 -0
- data/lib/ajax-datatables-rails/datatable/datatable.rb +10 -7
- data/lib/ajax-datatables-rails/datatable/simple_order.rb +17 -2
- data/lib/ajax-datatables-rails/datatable/simple_search.rb +3 -0
- data/lib/ajax-datatables-rails/orm/active_record.rb +14 -5
- data/lib/ajax-datatables-rails/version.rb +3 -1
- data/lib/ajax_datatables_rails.rb +15 -0
- data/lib/generators/datatable/config_generator.rb +2 -0
- data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +5 -0
- data/lib/generators/rails/datatable_generator.rb +6 -5
- data/lib/generators/rails/templates/datatable.rb +1 -15
- data/spec/ajax-datatables-rails/base_spec.rb +23 -26
- data/spec/ajax-datatables-rails/datatable/column_spec.rb +68 -23
- data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +1 -1
- data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +29 -2
- data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +1 -1
- data/spec/ajax-datatables-rails/extended_spec.rb +3 -3
- data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +94 -35
- data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +6 -6
- data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +43 -0
- data/spec/ajax-datatables-rails/orm/active_record_spec.rb +1 -1
- data/spec/factories/user.rb +1 -1
- data/spec/install_oracle.sh +2 -2
- data/spec/spec_helper.rb +8 -3
- data/spec/support/datatable_cond_date.rb +5 -0
- data/spec/support/datatable_cond_numeric.rb +41 -0
- data/spec/support/datatable_cond_proc.rb +11 -0
- data/spec/support/datatable_cond_string.rb +23 -0
- data/spec/support/datatable_order_nulls_last.rb +5 -0
- data/spec/support/test_helpers.rb +13 -88
- metadata +28 -13
- data/lib/ajax-datatables-rails/datatable/column_date_filter.rb +0 -41
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AjaxDatatablesRails
|
4
|
+
module Datatable
|
5
|
+
class Column
|
6
|
+
module DateFilter
|
7
|
+
|
8
|
+
class DateRange
|
9
|
+
attr_reader :begin, :end
|
10
|
+
|
11
|
+
def initialize(date_start, date_end)
|
12
|
+
@begin = date_start
|
13
|
+
@end = date_end
|
14
|
+
end
|
15
|
+
|
16
|
+
def exclude_end?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Add delimiter option to handle range search
|
22
|
+
def delimiter
|
23
|
+
@view_column[:delimiter] || '-'
|
24
|
+
end
|
25
|
+
|
26
|
+
def empty_range_search?
|
27
|
+
(formated_value == delimiter) || (range_start.blank? && range_end.blank?)
|
28
|
+
end
|
29
|
+
|
30
|
+
# A range value is in form '<range_start><delimiter><range_end>'
|
31
|
+
# This returns <range_start>
|
32
|
+
def range_start
|
33
|
+
@range_start ||= formated_value.split(delimiter)[0]
|
34
|
+
end
|
35
|
+
|
36
|
+
# A range value is in form '<range_start><delimiter><range_end>'
|
37
|
+
# This returns <range_end>
|
38
|
+
def range_end
|
39
|
+
@range_end ||= formated_value.split(delimiter)[1]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Do a range search
|
43
|
+
def date_range_search
|
44
|
+
return nil if empty_range_search?
|
45
|
+
table[field].between(DateRange.new(range_start_casted, range_end_casted))
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def non_regex_search
|
51
|
+
if cond == :date_range
|
52
|
+
date_range_search
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def range_start_casted
|
59
|
+
range_start.blank? ? parse_date('01/01/1970') : parse_date(range_start)
|
60
|
+
end
|
61
|
+
|
62
|
+
def range_end_casted
|
63
|
+
range_end.blank? ? Time.current : parse_date("#{range_end} 23:59:59")
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_date(date)
|
67
|
+
if Time.zone
|
68
|
+
Time.zone.parse(date)
|
69
|
+
else
|
70
|
+
Time.parse(date)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AjaxDatatablesRails
|
4
|
+
module Datatable
|
5
|
+
class Column
|
6
|
+
module Order
|
7
|
+
|
8
|
+
def orderable?
|
9
|
+
@view_column.fetch(:orderable, true)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Add sort_field option to allow overriding of sort field
|
13
|
+
def sort_field
|
14
|
+
@view_column[:sort_field] || field
|
15
|
+
end
|
16
|
+
|
17
|
+
def sort_query
|
18
|
+
custom_field? ? source : "#{table.name}.#{sort_field}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Add option to sort null values last
|
22
|
+
def nulls_last?
|
23
|
+
@view_column.fetch(:nulls_last, false)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AjaxDatatablesRails
|
4
|
+
module Datatable
|
5
|
+
class Column
|
6
|
+
module Search
|
7
|
+
|
8
|
+
def searchable?
|
9
|
+
@view_column.fetch(:searchable, true)
|
10
|
+
end
|
11
|
+
|
12
|
+
def cond
|
13
|
+
@view_column[:cond] || :like
|
14
|
+
end
|
15
|
+
|
16
|
+
def filter
|
17
|
+
@view_column[:cond].call(self, formated_value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def search
|
21
|
+
@search ||= SimpleSearch.new(options[:search])
|
22
|
+
end
|
23
|
+
|
24
|
+
def searched?
|
25
|
+
search.value.present?
|
26
|
+
end
|
27
|
+
|
28
|
+
def search_query
|
29
|
+
search.regexp? ? regex_search : non_regex_search
|
30
|
+
end
|
31
|
+
|
32
|
+
# Add use_regex option to allow bypassing of regex search
|
33
|
+
def use_regex?
|
34
|
+
@view_column.fetch(:use_regex, true)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Using multi-select filters in JQuery Datatable auto-enables regex_search.
|
40
|
+
# Unfortunately regex_search doesn't work when filtering on primary keys with integer.
|
41
|
+
# It generates this kind of query : AND ("regions"."id" ~ '2|3') which throws an error :
|
42
|
+
# operator doesn't exist : integer ~ unknown
|
43
|
+
# The solution is to bypass regex_search and use non_regex_search with :in operator
|
44
|
+
def regex_search
|
45
|
+
if use_regex?
|
46
|
+
::Arel::Nodes::Regexp.new((custom_field? ? field : table[field]), ::Arel::Nodes.build_quoted(formated_value))
|
47
|
+
else
|
48
|
+
non_regex_search
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def non_regex_search
|
53
|
+
case cond
|
54
|
+
when Proc
|
55
|
+
filter
|
56
|
+
when :eq, :not_eq, :lt, :gt, :lteq, :gteq, :in
|
57
|
+
numeric_search
|
58
|
+
when :null_value
|
59
|
+
null_value_search
|
60
|
+
when :start_with
|
61
|
+
casted_column.matches("#{formated_value}%")
|
62
|
+
when :end_with
|
63
|
+
casted_column.matches("%#{formated_value}")
|
64
|
+
when :like
|
65
|
+
casted_column.matches("%#{formated_value}%")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def null_value_search
|
70
|
+
if formated_value == '!NULL'
|
71
|
+
table[field].not_eq(nil)
|
72
|
+
else
|
73
|
+
table[field].eq(nil)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def numeric_search
|
78
|
+
if custom_field?
|
79
|
+
::Arel::Nodes::SqlLiteral.new(field).eq(formated_value)
|
80
|
+
else
|
81
|
+
table[field].send(cond, formated_value)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module AjaxDatatablesRails
|
2
4
|
module Datatable
|
3
5
|
|
4
|
-
TRUE_VALUE = 'true'
|
6
|
+
TRUE_VALUE = 'true'
|
5
7
|
|
6
8
|
class Datatable
|
7
9
|
attr_reader :datatable, :options
|
@@ -55,16 +57,16 @@ module AjaxDatatablesRails
|
|
55
57
|
per_page != -1
|
56
58
|
end
|
57
59
|
|
58
|
-
def
|
59
|
-
(
|
60
|
+
def per_page
|
61
|
+
options.fetch(:length, 10).to_i
|
60
62
|
end
|
61
63
|
|
62
|
-
def
|
63
|
-
(
|
64
|
+
def offset
|
65
|
+
options.fetch(:start, 0).to_i
|
64
66
|
end
|
65
67
|
|
66
|
-
def
|
67
|
-
|
68
|
+
def page
|
69
|
+
(offset / per_page) + 1
|
68
70
|
end
|
69
71
|
|
70
72
|
def get_param(param)
|
@@ -74,6 +76,7 @@ module AjaxDatatablesRails
|
|
74
76
|
options[param].to_unsafe_h.with_indifferent_access
|
75
77
|
end
|
76
78
|
end
|
79
|
+
|
77
80
|
end
|
78
81
|
end
|
79
82
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module AjaxDatatablesRails
|
2
4
|
module Datatable
|
3
5
|
class SimpleOrder
|
@@ -10,7 +12,11 @@ module AjaxDatatablesRails
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def query(sort_column)
|
13
|
-
|
15
|
+
if sort_nulls_last?
|
16
|
+
"CASE WHEN #{sort_column} IS NULL THEN 1 ELSE 0 END, #{sort_column} #{direction}"
|
17
|
+
else
|
18
|
+
"#{sort_column} #{direction}"
|
19
|
+
end
|
14
20
|
end
|
15
21
|
|
16
22
|
def column
|
@@ -18,7 +24,7 @@ module AjaxDatatablesRails
|
|
18
24
|
end
|
19
25
|
|
20
26
|
def direction
|
21
|
-
DIRECTIONS.find { |dir| dir ==
|
27
|
+
DIRECTIONS.find { |dir| dir == column_direction } || 'ASC'
|
22
28
|
end
|
23
29
|
|
24
30
|
private
|
@@ -26,6 +32,15 @@ module AjaxDatatablesRails
|
|
26
32
|
def column_index
|
27
33
|
@options[:column]
|
28
34
|
end
|
35
|
+
|
36
|
+
def column_direction
|
37
|
+
@options[:dir].upcase
|
38
|
+
end
|
39
|
+
|
40
|
+
def sort_nulls_last?
|
41
|
+
column.nulls_last? || AjaxDatatablesRails.config.nulls_last == true
|
42
|
+
end
|
43
|
+
|
29
44
|
end
|
30
45
|
end
|
31
46
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module AjaxDatatablesRails
|
2
4
|
module ORM
|
3
5
|
module ActiveRecord
|
@@ -10,13 +12,16 @@ module AjaxDatatablesRails
|
|
10
12
|
records.where(build_conditions)
|
11
13
|
end
|
12
14
|
|
15
|
+
# rubocop:disable Style/EachWithObject
|
13
16
|
def sort_records(records)
|
14
17
|
sort_by = datatable.orders.inject([]) do |queries, order|
|
15
18
|
column = order.column
|
16
|
-
queries << order.query(column.sort_query) if column
|
19
|
+
queries << order.query(column.sort_query) if column && column.orderable?
|
20
|
+
queries
|
17
21
|
end
|
18
|
-
records.order(sort_by.join(
|
22
|
+
records.order(Arel.sql(sort_by.join(', ')))
|
19
23
|
end
|
24
|
+
# rubocop:enable Style/EachWithObject
|
20
25
|
|
21
26
|
def paginate_records(records)
|
22
27
|
records.offset(datatable.offset).limit(datatable.per_page)
|
@@ -33,20 +38,24 @@ module AjaxDatatablesRails
|
|
33
38
|
end
|
34
39
|
|
35
40
|
def build_conditions_for_datatable
|
36
|
-
search_for = datatable.search.value.split(' ')
|
37
41
|
criteria = search_for.inject([]) do |crit, atom|
|
38
|
-
search = Datatable::SimpleSearch.new(
|
42
|
+
search = Datatable::SimpleSearch.new(value: atom, regex: datatable.search.regexp?)
|
39
43
|
crit << searchable_columns.map do |simple_column|
|
40
44
|
simple_column.search = search
|
41
45
|
simple_column.search_query
|
42
46
|
end.reduce(:or)
|
43
|
-
end.reduce(:and)
|
47
|
+
end.compact.reduce(:and)
|
44
48
|
criteria
|
45
49
|
end
|
46
50
|
|
47
51
|
def build_conditions_for_selected_columns
|
48
52
|
search_columns.map(&:search_query).compact.reduce(:and)
|
49
53
|
end
|
54
|
+
|
55
|
+
def search_for
|
56
|
+
datatable.search.value.split(global_search_delimiter)
|
57
|
+
end
|
58
|
+
|
50
59
|
end
|
51
60
|
end
|
52
61
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AjaxDatatablesRails
|
4
|
+
require 'ajax-datatables-rails/version'
|
5
|
+
require 'ajax-datatables-rails/config'
|
6
|
+
require 'ajax-datatables-rails/base'
|
7
|
+
require 'ajax-datatables-rails/datatable/datatable'
|
8
|
+
require 'ajax-datatables-rails/datatable/simple_search'
|
9
|
+
require 'ajax-datatables-rails/datatable/simple_order'
|
10
|
+
require 'ajax-datatables-rails/datatable/column/search'
|
11
|
+
require 'ajax-datatables-rails/datatable/column/order'
|
12
|
+
require 'ajax-datatables-rails/datatable/column/date_filter' unless AjaxDatatablesRails.old_rails?
|
13
|
+
require 'ajax-datatables-rails/datatable/column'
|
14
|
+
require 'ajax-datatables-rails/orm/active_record'
|
15
|
+
end
|
@@ -1,7 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
AjaxDatatablesRails.configure do |config|
|
2
4
|
# available options for db_adapter are: :pg, :mysql, :mysql2, :sqlite, :sqlite3
|
3
5
|
# config.db_adapter = :pg
|
4
6
|
|
7
|
+
# Or you can use your rails environment adapter if you want a generic dev and production
|
8
|
+
# config.db_adapter = Rails.configuration.database_configuration[Rails.env]['adapter'].to_sym
|
9
|
+
|
5
10
|
# available options for orm are: :active_record, :mongoid
|
6
11
|
# config.orm = :active_record
|
7
12
|
end
|
@@ -1,16 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rails/generators'
|
2
4
|
|
3
5
|
module Rails
|
4
6
|
module Generators
|
5
7
|
class DatatableGenerator < ::Rails::Generators::Base
|
6
8
|
desc 'Creates a *_datatable model in the app/datatables directory.'
|
7
|
-
source_root File.expand_path('
|
9
|
+
source_root File.expand_path('templates', __dir__)
|
8
10
|
argument :name, type: :string
|
9
11
|
|
10
12
|
def generate_datatable
|
11
|
-
template 'datatable.rb', File.join(
|
12
|
-
'app/datatables', "#{datatable_path}.rb"
|
13
|
-
)
|
13
|
+
template 'datatable.rb', File.join('app', 'datatables', "#{datatable_path}.rb")
|
14
14
|
end
|
15
15
|
|
16
16
|
def datatable_name
|
@@ -18,10 +18,11 @@ module Rails
|
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
21
|
+
|
21
22
|
def datatable_path
|
22
23
|
"#{name.underscore}_datatable"
|
23
24
|
end
|
24
25
|
|
25
26
|
end
|
26
27
|
end
|
27
|
-
end
|
28
|
+
end
|
@@ -19,23 +19,9 @@ class <%= datatable_name %> < AjaxDatatablesRails::Base
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
private
|
23
|
-
|
24
22
|
def get_raw_records
|
25
23
|
# insert query here
|
24
|
+
# User.all
|
26
25
|
end
|
27
26
|
|
28
|
-
# ==== These methods represent the basic operations to perform on records
|
29
|
-
# and feel free to override them
|
30
|
-
|
31
|
-
# def filter_records(records)
|
32
|
-
# end
|
33
|
-
|
34
|
-
# def sort_records(records)
|
35
|
-
# end
|
36
|
-
|
37
|
-
# def paginate_records(records)
|
38
|
-
# end
|
39
|
-
|
40
|
-
# ==== Insert 'presenter'-like methods below if necessary
|
41
27
|
end
|