ajax-datatables-rails 0.4.3 → 1.3.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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +120 -0
  3. data/.rubocop.yml +17 -7
  4. data/Appraisals +15 -20
  5. data/CHANGELOG.md +54 -1
  6. data/Gemfile +0 -5
  7. data/Guardfile +16 -0
  8. data/README.md +238 -112
  9. data/Rakefile +1 -0
  10. data/ajax-datatables-rails.gemspec +24 -20
  11. data/bin/_guard-core +29 -0
  12. data/bin/appraisal +29 -0
  13. data/bin/bundle +114 -0
  14. data/bin/guard +29 -0
  15. data/bin/rake +29 -0
  16. data/bin/rspec +29 -0
  17. data/bin/rubocop +29 -0
  18. data/doc/migrate.md +97 -0
  19. data/doc/webpack.md +7 -2
  20. data/gemfiles/{rails_5.2.0.gemfile → rails_5.2.4.gemfile} +3 -5
  21. data/gemfiles/{rails_5.0.7.gemfile → rails_6.0.3.gemfile} +4 -6
  22. data/gemfiles/{rails_5.1.6.gemfile → rails_6.1.0.gemfile} +4 -6
  23. data/lib/ajax-datatables-rails.rb +12 -1
  24. data/lib/ajax-datatables-rails/active_record.rb +7 -0
  25. data/lib/ajax-datatables-rails/base.rb +47 -46
  26. data/lib/ajax-datatables-rails/datatable.rb +6 -0
  27. data/lib/ajax-datatables-rails/datatable/column.rb +65 -20
  28. data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +12 -21
  29. data/lib/ajax-datatables-rails/datatable/column/order.rb +1 -1
  30. data/lib/ajax-datatables-rails/datatable/column/search.rb +37 -22
  31. data/lib/ajax-datatables-rails/datatable/datatable.rb +16 -7
  32. data/lib/ajax-datatables-rails/datatable/simple_order.rb +23 -10
  33. data/lib/ajax-datatables-rails/datatable/simple_search.rb +2 -0
  34. data/lib/ajax-datatables-rails/error.rb +9 -0
  35. data/lib/ajax-datatables-rails/orm.rb +6 -0
  36. data/lib/ajax-datatables-rails/orm/active_record.rb +11 -12
  37. data/lib/ajax-datatables-rails/version.rb +13 -1
  38. data/lib/generators/rails/templates/datatable.rb +1 -1
  39. data/spec/ajax-datatables-rails/base_spec.rb +129 -93
  40. data/spec/ajax-datatables-rails/datatable/column_spec.rb +105 -37
  41. data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +71 -31
  42. data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +36 -14
  43. data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +4 -2
  44. data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +315 -272
  45. data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +9 -8
  46. data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +17 -14
  47. data/spec/factories/user.rb +3 -1
  48. data/spec/install_oracle.sh +9 -3
  49. data/spec/spec_helper.rb +33 -28
  50. data/spec/support/datatables/complex_datatable.rb +31 -0
  51. data/spec/support/datatables/complex_datatable_array.rb +16 -0
  52. data/spec/support/{datatable_cond_date.rb → datatables/datatable_cond_date.rb} +2 -0
  53. data/spec/support/{datatable_cond_numeric.rb → datatables/datatable_cond_numeric.rb} +3 -1
  54. data/spec/support/{datatable_cond_proc.rb → datatables/datatable_cond_proc.rb} +2 -0
  55. data/spec/support/{datatable_cond_string.rb → datatables/datatable_cond_string.rb} +9 -1
  56. data/spec/support/datatables/datatable_cond_unknown.rb +7 -0
  57. data/spec/support/{datatable_order_nulls_last.rb → datatables/datatable_order_nulls_last.rb} +2 -0
  58. data/spec/support/{test_helpers.rb → helpers/params.rb} +17 -42
  59. data/spec/support/{test_models.rb → models/user.rb} +2 -0
  60. data/spec/support/schema.rb +3 -1
  61. metadata +76 -75
  62. data/.travis.yml +0 -80
  63. data/gemfiles/rails_4.0.13.gemfile +0 -14
  64. data/gemfiles/rails_4.1.16.gemfile +0 -14
  65. data/gemfiles/rails_4.2.10.gemfile +0 -14
  66. data/lib/ajax-datatables-rails/config.rb +0 -31
  67. data/lib/ajax_datatables_rails.rb +0 -15
  68. data/lib/generators/datatable/config_generator.rb +0 -19
  69. data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -12
  70. data/spec/ajax-datatables-rails/configuration_spec.rb +0 -43
  71. data/spec/ajax-datatables-rails/extended_spec.rb +0 -20
  72. data/spec/ajax-datatables-rails/orm/active_record_spec.rb +0 -25
@@ -11,7 +11,7 @@ module AjaxDatatablesRails
11
11
 
12
12
  # Add sort_field option to allow overriding of sort field
13
13
  def sort_field
14
- @view_column[:sort_field] || field
14
+ @view_column.fetch(:sort_field, field)
15
15
  end
16
16
 
17
17
  def sort_query
@@ -5,19 +5,21 @@ module AjaxDatatablesRails
5
5
  class Column
6
6
  module Search
7
7
 
8
- SMALLEST_PQ_INTEGER = -2147483648
9
- LARGEST_PQ_INTEGER = 2147483647
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[:cond] || :like
18
+ @view_column.fetch(:cond, :like)
17
19
  end
18
20
 
19
21
  def filter
20
- @view_column[:cond].call(self, formated_value)
22
+ @view_column[:cond].call(self, formatted_value)
21
23
  end
22
24
 
23
25
  def search
@@ -46,33 +48,39 @@ 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(formated_value))
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
- is_searchable_integer? ? raw_search(cond) : empty_search
61
- when :null_value
62
- null_value_search
63
+ searchable_integer? ? raw_search(cond) : empty_search
63
64
  when :start_with
64
- casted_column.matches("#{formated_value}%")
65
+ text_search("#{formatted_value}%")
65
66
  when :end_with
66
- casted_column.matches("%#{formated_value}")
67
+ text_search("%#{formatted_value}")
67
68
  when :like
68
- casted_column.matches("%#{formated_value}%")
69
+ text_search("%#{formatted_value}%")
69
70
  when :string_eq
70
71
  raw_search(:eq)
72
+ when :string_in
73
+ raw_search(:in)
74
+ when :null_value
75
+ null_value_search
76
+ when :date_range
77
+ date_range_search
71
78
  end
72
79
  end
80
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
73
81
 
74
82
  def null_value_search
75
- if formated_value == '!NULL'
83
+ if formatted_value == NOT_NULL_VALUE
76
84
  table[field].not_eq(nil)
77
85
  else
78
86
  table[field].eq(nil)
@@ -81,31 +89,38 @@ module AjaxDatatablesRails
81
89
 
82
90
  def raw_search(cond)
83
91
  if custom_field?
84
- ::Arel::Nodes::SqlLiteral.new(field).eq(formated_value)
92
+ ::Arel::Nodes::SqlLiteral.new(field).eq(formatted_value)
85
93
  else
86
- table[field].send(cond, formated_value)
94
+ table[field].send(cond, formatted_value)
87
95
  end
88
96
  end
89
97
 
98
+ def text_search(value)
99
+ casted_column.matches(value)
100
+ end
101
+
90
102
  def empty_search
91
- casted_column.matches('')
103
+ casted_column.matches(EMPTY_VALUE)
92
104
  end
93
105
 
94
- def is_searchable_integer?
95
- if formated_value.is_a?(Array)
96
- valids = formated_value.map { |v| is_integer?(v) && !is_out_of_range?(v) }
106
+ def searchable_integer?
107
+ if formatted_value.is_a?(Array)
108
+ valids = formatted_value.map { |v| integer?(v) && !out_of_range?(v) }
97
109
  !valids.include?(false)
98
110
  else
99
- is_integer?(formated_value) && !is_out_of_range?(formated_value)
111
+ integer?(formatted_value) && !out_of_range?(formatted_value)
100
112
  end
101
113
  end
102
114
 
103
- def is_out_of_range?(search_value)
115
+ def out_of_range?(search_value)
104
116
  Integer(search_value) > LARGEST_PQ_INTEGER || Integer(search_value) < SMALLEST_PQ_INTEGER
105
117
  end
106
118
 
107
- def is_integer?(string)
108
- true if Integer(string) rescue false
119
+ def integer?(string)
120
+ Integer(string)
121
+ true
122
+ rescue ArgumentError
123
+ false
109
124
  end
110
125
 
111
126
  end
@@ -2,11 +2,8 @@
2
2
 
3
3
  module AjaxDatatablesRails
4
4
  module Datatable
5
-
6
- TRUE_VALUE = 'true'
7
-
8
5
  class Datatable
9
- attr_reader :datatable, :options
6
+ attr_reader :options
10
7
 
11
8
  def initialize(datatable)
12
9
  @datatable = datatable
@@ -43,7 +40,7 @@ module AjaxDatatablesRails
43
40
 
44
41
  def columns
45
42
  @columns ||= get_param(:columns).map do |index, column_options|
46
- Column.new(datatable, index, column_options)
43
+ Column.new(@datatable, index, column_options)
47
44
  end
48
45
  end
49
46
 
@@ -70,13 +67,25 @@ module AjaxDatatablesRails
70
67
  end
71
68
 
72
69
  def get_param(param)
73
- if AjaxDatatablesRails.old_rails?
74
- options[param]
70
+ return {} if options[param].nil?
71
+
72
+ if options[param].is_a? Array
73
+ hash = {}
74
+ options[param].each_with_index { |value, index| hash[index] = value }
75
+ hash
75
76
  else
76
77
  options[param].to_unsafe_h.with_indifferent_access
77
78
  end
78
79
  end
79
80
 
81
+ def db_adapter
82
+ @datatable.db_adapter
83
+ end
84
+
85
+ def nulls_last
86
+ @datatable.nulls_last
87
+ end
88
+
80
89
  end
81
90
  end
82
91
  end
@@ -4,19 +4,19 @@ module AjaxDatatablesRails
4
4
  module Datatable
5
5
  class SimpleOrder
6
6
 
7
- DIRECTIONS = %w[DESC ASC].freeze
7
+ DIRECTION_ASC = 'ASC'
8
+ DIRECTION_DESC = 'DESC'
9
+ DIRECTIONS = [DIRECTION_ASC, DIRECTION_DESC].freeze
8
10
 
9
11
  def initialize(datatable, options = {})
10
- @datatable = datatable
11
- @options = options
12
+ @datatable = datatable
13
+ @options = options
14
+ @adapter = datatable.db_adapter
15
+ @nulls_last = datatable.nulls_last
12
16
  end
13
17
 
14
18
  def query(sort_column)
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
19
+ [sort_column, direction, nulls_last_sql].compact.join(' ')
20
20
  end
21
21
 
22
22
  def column
@@ -24,7 +24,7 @@ module AjaxDatatablesRails
24
24
  end
25
25
 
26
26
  def direction
27
- DIRECTIONS.find { |dir| dir == column_direction } || 'ASC'
27
+ DIRECTIONS.find { |dir| dir == column_direction } || DIRECTION_ASC
28
28
  end
29
29
 
30
30
  private
@@ -38,7 +38,20 @@ module AjaxDatatablesRails
38
38
  end
39
39
 
40
40
  def sort_nulls_last?
41
- column.nulls_last? || AjaxDatatablesRails.config.nulls_last == true
41
+ column.nulls_last? || @nulls_last == true
42
+ end
43
+
44
+ def nulls_last_sql
45
+ return unless sort_nulls_last?
46
+
47
+ case @adapter
48
+ when :pg, :postgresql, :postgres, :oracle
49
+ 'NULLS LAST'
50
+ when :mysql, :mysql2, :sqlite, :sqlite3
51
+ 'IS NULL'
52
+ else
53
+ raise "unsupported database adapter: #{@adapter}"
54
+ end
42
55
  end
43
56
 
44
57
  end
@@ -4,6 +4,8 @@ module AjaxDatatablesRails
4
4
  module Datatable
5
5
  class SimpleSearch
6
6
 
7
+ TRUE_VALUE = 'true'
8
+
7
9
  def initialize(options = {})
8
10
  @options = options
9
11
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AjaxDatatablesRails
4
+ module Error
5
+ class BaseError < StandardError; end
6
+ class InvalidSearchColumn < BaseError; end
7
+ class InvalidSearchCondition < BaseError; end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AjaxDatatablesRails
4
+ module ORM
5
+ end
6
+ end
@@ -4,15 +4,11 @@ module AjaxDatatablesRails
4
4
  module ORM
5
5
  module ActiveRecord
6
6
 
7
- def fetch_records
8
- get_raw_records
9
- end
10
-
11
7
  def filter_records(records)
12
8
  records.where(build_conditions)
13
9
  end
14
10
 
15
- # rubocop:disable Style/EachWithObject
11
+ # rubocop:disable Style/EachWithObject, Style/SafeNavigation
16
12
  def sort_records(records)
17
13
  sort_by = datatable.orders.inject([]) do |queries, order|
18
14
  column = order.column
@@ -21,7 +17,7 @@ module AjaxDatatablesRails
21
17
  end
22
18
  records.order(Arel.sql(sort_by.join(', ')))
23
19
  end
24
- # rubocop:enable Style/EachWithObject
20
+ # rubocop:enable Style/EachWithObject, Style/SafeNavigation
25
21
 
26
22
  def paginate_records(records)
27
23
  records.offset(datatable.offset).limit(datatable.per_page)
@@ -30,23 +26,26 @@ module AjaxDatatablesRails
30
26
  # ----------------- SEARCH HELPER METHODS --------------------
31
27
 
32
28
  def build_conditions
33
- if datatable.searchable?
34
- build_conditions_for_datatable
35
- else
36
- build_conditions_for_selected_columns
29
+ @build_conditions ||= begin
30
+ criteria = [build_conditions_for_selected_columns]
31
+ criteria << build_conditions_for_datatable if datatable.searchable?
32
+ criteria.compact.reduce(:and)
37
33
  end
38
34
  end
39
35
 
36
+ # rubocop:disable Metrics/AbcSize
40
37
  def build_conditions_for_datatable
38
+ columns = searchable_columns.reject(&:searched?)
41
39
  criteria = search_for.inject([]) do |crit, atom|
42
40
  search = Datatable::SimpleSearch.new(value: atom, regex: datatable.search.regexp?)
43
- crit << searchable_columns.map do |simple_column|
41
+ crit << columns.map do |simple_column|
44
42
  simple_column.search = search
45
43
  simple_column.search_query
46
- end.reduce(:or)
44
+ end.compact.reduce(:or)
47
45
  end.compact.reduce(:and)
48
46
  criteria
49
47
  end
48
+ # rubocop:enable Metrics/AbcSize
50
49
 
51
50
  def build_conditions_for_selected_columns
52
51
  search_columns.map(&:search_query).compact.reduce(:and)
@@ -1,5 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AjaxDatatablesRails
4
- VERSION = '0.4.3'
4
+
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ module VERSION
10
+ MAJOR = 1
11
+ MINOR = 3
12
+ TINY = 1
13
+ PRE = nil
14
+
15
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
16
+ end
5
17
  end
@@ -1,4 +1,4 @@
1
- class <%= datatable_name %> < AjaxDatatablesRails::Base
1
+ class <%= datatable_name %> < AjaxDatatablesRails::ActiveRecord
2
2
 
3
3
  def view_columns
4
4
  # Declare strings in this format: ModelName.column_name
@@ -1,54 +1,58 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe AjaxDatatablesRails::Base do
5
+ RSpec.describe AjaxDatatablesRails::Base do
4
6
 
5
7
  describe 'an instance' do
6
- let(:view) { double('view', params: sample_params) }
7
-
8
- it 'requires a view_context' do
8
+ it 'requires a hash of params' do
9
9
  expect { described_class.new }.to raise_error ArgumentError
10
10
  end
11
11
 
12
12
  it 'accepts an options hash' do
13
- datatable = described_class.new(view, foo: 'bar')
13
+ datatable = described_class.new(sample_params, foo: 'bar')
14
14
  expect(datatable.options).to eq(foo: 'bar')
15
15
  end
16
16
  end
17
17
 
18
- context 'Public API' do
19
- let(:view) { double('view', params: sample_params) }
20
-
18
+ describe 'User API' do
21
19
  describe '#view_columns' do
22
- it 'raises an error if not defined by the user' do
23
- datatable = described_class.new(view)
24
- expect { datatable.view_columns }.to raise_error NotImplementedError
20
+ context 'when method is not defined by the user' do
21
+ it 'raises an error' do
22
+ datatable = described_class.new(sample_params)
23
+ expect { datatable.view_columns }.to raise_error NotImplementedError
24
+ end
25
25
  end
26
26
 
27
27
  context 'child class implements view_columns' do
28
28
  it 'expects a hash based defining columns' do
29
- datatable = ComplexDatatable.new(view)
29
+ datatable = ComplexDatatable.new(sample_params)
30
30
  expect(datatable.view_columns).to be_a(Hash)
31
31
  end
32
32
  end
33
33
  end
34
34
 
35
35
  describe '#get_raw_records' do
36
- it 'raises an error if not defined by the user' do
37
- datatable = described_class.new(view)
38
- expect { datatable.get_raw_records }.to raise_error NotImplementedError
36
+ context 'when method is not defined by the user' do
37
+ it 'raises an error' do
38
+ datatable = described_class.new(sample_params)
39
+ expect { datatable.get_raw_records }.to raise_error NotImplementedError
40
+ end
39
41
  end
40
42
  end
41
43
 
42
44
  describe '#data' do
43
- it 'raises an error if not defined by the user' do
44
- datatable = described_class.new(view)
45
- expect { datatable.data }.to raise_error NotImplementedError
45
+ context 'when method is not defined by the user' do
46
+ it 'raises an error' do
47
+ datatable = described_class.new(sample_params)
48
+ expect { datatable.data }.to raise_error NotImplementedError
49
+ end
46
50
  end
47
51
 
48
52
  context 'when data is defined as a hash' do
49
- let(:datatable) { ComplexDatatable.new(view) }
53
+ let(:datatable) { ComplexDatatable.new(sample_params) }
50
54
 
51
- it 'should return an array of hashes' do
55
+ it 'returns an array of hashes' do
52
56
  create_list(:user, 5)
53
57
  expect(datatable.data).to be_a(Array)
54
58
  expect(datatable.data.size).to eq 5
@@ -56,9 +60,9 @@ describe AjaxDatatablesRails::Base do
56
60
  expect(item).to be_a(Hash)
57
61
  end
58
62
 
59
- it 'should html escape data' do
63
+ it 'htmls escape data' do
60
64
  create(:user, first_name: 'Name "><img src=x onerror=alert("first_name")>', last_name: 'Name "><img src=x onerror=alert("last_name")>')
61
- data = datatable.send(:sanitize, datatable.data)
65
+ data = datatable.send(:sanitize_data, datatable.data)
62
66
  item = data.first
63
67
  expect(item[:first_name]).to eq 'Name &quot;&gt;&lt;img src=x onerror=alert(&quot;first_name&quot;)&gt;'
64
68
  expect(item[:last_name]).to eq 'Name &quot;&gt;&lt;img src=x onerror=alert(&quot;last_name&quot;)&gt;'
@@ -66,9 +70,9 @@ describe AjaxDatatablesRails::Base do
66
70
  end
67
71
 
68
72
  context 'when data is defined as a array' do
69
- let(:datatable) { ComplexDatatableArray.new(view) }
73
+ let(:datatable) { ComplexDatatableArray.new(sample_params) }
70
74
 
71
- it 'should return an array of arrays' do
75
+ it 'returns an array of arrays' do
72
76
  create_list(:user, 5)
73
77
  expect(datatable.data).to be_a(Array)
74
78
  expect(datatable.data.size).to eq 5
@@ -76,20 +80,103 @@ describe AjaxDatatablesRails::Base do
76
80
  expect(item).to be_a(Array)
77
81
  end
78
82
 
79
- it 'should html escape data' do
83
+ it 'htmls escape data' do
80
84
  create(:user, first_name: 'Name "><img src=x onerror=alert("first_name")>', last_name: 'Name "><img src=x onerror=alert("last_name")>')
81
- data = datatable.send(:sanitize, datatable.data)
85
+ data = datatable.send(:sanitize_data, datatable.data)
82
86
  item = data.first
83
87
  expect(item[2]).to eq 'Name &quot;&gt;&lt;img src=x onerror=alert(&quot;first_name&quot;)&gt;'
84
88
  expect(item[3]).to eq 'Name &quot;&gt;&lt;img src=x onerror=alert(&quot;last_name&quot;)&gt;'
85
89
  end
86
90
  end
87
91
  end
92
+ end
93
+
94
+ describe 'ORM API' do
95
+ context 'when ORM is not implemented' do
96
+ let(:datatable) { AjaxDatatablesRails::Base.new(sample_params) }
97
+
98
+ describe '#fetch_records' do
99
+ it 'raises an error if it does not include an ORM module' do
100
+ expect { datatable.fetch_records }.to raise_error NotImplementedError
101
+ end
102
+ end
103
+
104
+ describe '#filter_records' do
105
+ it 'raises an error if it does not include an ORM module' do
106
+ expect { datatable.filter_records([]) }.to raise_error NotImplementedError
107
+ end
108
+ end
109
+
110
+ describe '#sort_records' do
111
+ it 'raises an error if it does not include an ORM module' do
112
+ expect { datatable.sort_records([]) }.to raise_error NotImplementedError
113
+ end
114
+ end
115
+
116
+ describe '#paginate_records' do
117
+ it 'raises an error if it does not include an ORM module' do
118
+ expect { datatable.paginate_records([]) }.to raise_error NotImplementedError
119
+ end
120
+ end
121
+ end
122
+
123
+ context 'when ORM is implemented' do
124
+ describe 'it allows method override' do
125
+ let(:datatable) do
126
+ datatable = Class.new(ComplexDatatable) do
127
+ def filter_records(records)
128
+ raise NotImplementedError.new('FOO')
129
+ end
130
+
131
+ def sort_records(records)
132
+ raise NotImplementedError.new('FOO')
133
+ end
134
+
135
+ def paginate_records(records)
136
+ raise NotImplementedError.new('FOO')
137
+ end
138
+ end
139
+ datatable.new(sample_params)
140
+ end
141
+
142
+ describe '#fetch_records' do
143
+ it 'calls #get_raw_records' do
144
+ expect(datatable).to receive(:get_raw_records) { User.all }
145
+ datatable.fetch_records
146
+ end
147
+
148
+ it 'returns a collection of records' do
149
+ expect(datatable).to receive(:get_raw_records) { User.all }
150
+ expect(datatable.fetch_records).to be_a(ActiveRecord::Relation)
151
+ end
152
+ end
153
+
154
+ describe '#filter_records' do
155
+ it {
156
+ expect { datatable.filter_records([]) }.to raise_error(NotImplementedError).with_message('FOO')
157
+ }
158
+ end
159
+
160
+ describe '#sort_records' do
161
+ it {
162
+ expect { datatable.sort_records([]) }.to raise_error(NotImplementedError).with_message('FOO')
163
+ }
164
+ end
165
+
166
+ describe '#paginate_records' do
167
+ it {
168
+ expect { datatable.paginate_records([]) }.to raise_error(NotImplementedError).with_message('FOO')
169
+ }
170
+ end
171
+ end
172
+ end
173
+ end
88
174
 
175
+ describe 'JSON format' do
89
176
  describe '#as_json' do
90
- let(:datatable) { ComplexDatatable.new(view) }
177
+ let(:datatable) { ComplexDatatable.new(sample_params) }
91
178
 
92
- it 'should return a hash' do
179
+ it 'returns a hash' do
93
180
  create_list(:user, 5)
94
181
  data = datatable.as_json
95
182
  expect(data[:recordsTotal]).to eq 5
@@ -99,9 +186,9 @@ describe AjaxDatatablesRails::Base do
99
186
  end
100
187
 
101
188
  context 'with additional_data' do
102
- it 'should return a hash' do
189
+ it 'returns a hash' do
103
190
  create_list(:user, 5)
104
- expect(datatable).to receive(:additional_data){ { foo: 'bar' } }
191
+ expect(datatable).to receive(:additional_data) { { foo: 'bar' } }
105
192
  data = datatable.as_json
106
193
  expect(data[:recordsTotal]).to eq 5
107
194
  expect(data[:recordsFiltered]).to eq 5
@@ -113,74 +200,23 @@ describe AjaxDatatablesRails::Base do
113
200
  end
114
201
  end
115
202
 
203
+ describe 'User helper methods' do
204
+ describe '#column_id' do
205
+ let(:datatable) { ComplexDatatable.new(sample_params) }
116
206
 
117
- context 'Private API' do
118
-
119
- let(:view) { double('view', params: sample_params) }
120
- let(:datatable) { ComplexDatatable.new(view) }
121
-
122
- before(:each) do
123
- allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:orm) { nil }
124
- end
125
-
126
- describe '#fetch_records' do
127
- it 'raises an error if it does not include an ORM module' do
128
- expect { datatable.send(:fetch_records) }.to raise_error NoMethodError
207
+ it 'returns column id from view_columns hash' do
208
+ expect(datatable.column_id(:username)).to eq(0)
209
+ expect(datatable.column_id('username')).to eq(0)
129
210
  end
130
211
  end
131
212
 
132
- describe '#filter_records' do
133
- it 'raises an error if it does not include an ORM module' do
134
- expect { datatable.send(:filter_records) }.to raise_error NoMethodError
135
- end
136
- end
137
-
138
- describe '#sort_records' do
139
- it 'raises an error if it does not include an ORM module' do
140
- expect { datatable.send(:sort_records) }.to raise_error NoMethodError
141
- end
142
- end
213
+ describe '#column_data' do
214
+ let(:datatable) { ComplexDatatable.new(sample_params) }
215
+ before { datatable.params[:columns]['0'][:search][:value] = 'doe' }
143
216
 
144
- describe '#paginate_records' do
145
- it 'raises an error if it does not include an ORM module' do
146
- expect { datatable.send(:paginate_records) }.to raise_error NoMethodError
147
- end
148
- end
149
-
150
- describe 'helper methods' do
151
- describe '#offset' do
152
- it 'defaults to 0' do
153
- default_view = double('view', params: {})
154
- datatable = described_class.new(default_view)
155
- expect(datatable.datatable.send(:offset)).to eq(0)
156
- end
157
-
158
- it 'matches the value on view params[:start]' do
159
- paginated_view = double('view', params: { start: '11' })
160
- datatable = described_class.new(paginated_view)
161
- expect(datatable.datatable.send(:offset)).to eq(11)
162
- end
163
- end
164
-
165
- describe '#page' do
166
- it 'calculates page number from params[:start] and #per_page' do
167
- paginated_view = double('view', params: { start: '11' })
168
- datatable = described_class.new(paginated_view)
169
- expect(datatable.datatable.send(:page)).to eq(2)
170
- end
171
- end
172
-
173
- describe '#per_page' do
174
- it 'defaults to 10' do
175
- datatable = described_class.new(view)
176
- expect(datatable.datatable.send(:per_page)).to eq(10)
177
- end
178
-
179
- it 'matches the value on view params[:length]' do
180
- other_view = double('view', params: { length: 20 })
181
- datatable = described_class.new(other_view)
182
- expect(datatable.datatable.send(:per_page)).to eq(20)
183
- end
217
+ it 'returns column data from params' do
218
+ expect(datatable.column_data(:username)).to eq('doe')
219
+ expect(datatable.column_data('username')).to eq('doe')
184
220
  end
185
221
  end
186
222
  end