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.
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