ajax-datatables-rails 0.3.1 → 0.4.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +26 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +1157 -0
  6. data/.travis.yml +68 -0
  7. data/Appraisals +34 -0
  8. data/Gemfile +5 -1
  9. data/LICENSE +17 -18
  10. data/README.md +239 -239
  11. data/Rakefile +1 -1
  12. data/ajax-datatables-rails.gemspec +31 -24
  13. data/gemfiles/rails_4.0.13.gemfile +14 -0
  14. data/gemfiles/rails_4.1.15.gemfile +14 -0
  15. data/gemfiles/rails_4.2.8.gemfile +13 -0
  16. data/gemfiles/rails_5.0.3.gemfile +13 -0
  17. data/gemfiles/rails_5.1.1.gemfile +13 -0
  18. data/lib/ajax-datatables-rails.rb +9 -8
  19. data/lib/ajax-datatables-rails/base.rb +80 -156
  20. data/lib/ajax-datatables-rails/config.rb +8 -5
  21. data/lib/ajax-datatables-rails/datatable/column.rb +169 -0
  22. data/lib/ajax-datatables-rails/datatable/column_date_filter.rb +41 -0
  23. data/lib/ajax-datatables-rails/datatable/datatable.rb +79 -0
  24. data/lib/ajax-datatables-rails/datatable/simple_order.rb +31 -0
  25. data/lib/ajax-datatables-rails/datatable/simple_search.rb +18 -0
  26. data/lib/ajax-datatables-rails/orm/active_record.rb +52 -0
  27. data/lib/ajax-datatables-rails/version.rb +1 -1
  28. data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +3 -3
  29. data/lib/generators/rails/datatable_generator.rb +7 -19
  30. data/lib/generators/rails/templates/datatable.rb +26 -14
  31. data/spec/ajax-datatables-rails/base_spec.rb +190 -0
  32. data/spec/ajax-datatables-rails/configuration_spec.rb +43 -0
  33. data/spec/ajax-datatables-rails/datatable/column_spec.rb +109 -0
  34. data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +87 -0
  35. data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +13 -0
  36. data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +17 -0
  37. data/spec/ajax-datatables-rails/extended_spec.rb +20 -0
  38. data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +439 -0
  39. data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +66 -0
  40. data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +34 -0
  41. data/spec/ajax-datatables-rails/orm/active_record_spec.rb +25 -0
  42. data/spec/factories/user.rb +9 -0
  43. data/spec/install_oracle.sh +12 -0
  44. data/spec/spec_helper.rb +75 -3
  45. data/spec/support/schema.rb +14 -0
  46. data/spec/support/test_helpers.rb +174 -0
  47. data/spec/support/test_models.rb +2 -0
  48. metadata +169 -37
  49. data/lib/ajax-datatables-rails/extensions/kaminari.rb +0 -12
  50. data/lib/ajax-datatables-rails/extensions/simple_paginator.rb +0 -12
  51. data/lib/ajax-datatables-rails/extensions/will_paginate.rb +0 -12
  52. data/lib/ajax-datatables-rails/models.rb +0 -6
  53. data/spec/ajax-datatables-rails/ajax_datatables_rails_spec.rb +0 -351
  54. data/spec/ajax-datatables-rails/kaminari_spec.rb +0 -35
  55. data/spec/ajax-datatables-rails/models_spec.rb +0 -10
  56. data/spec/ajax-datatables-rails/simple_paginator_spec.rb +0 -32
  57. data/spec/ajax-datatables-rails/will_paginate_spec.rb +0 -28
  58. data/spec/schema.rb +0 -35
  59. data/spec/test_models.rb +0 -21
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'bundler/gem_tasks'
3
3
  require 'rspec/core/rake_task'
4
4
 
5
5
  RSpec::Core::RakeTask.new(:spec)
6
- task :default => :spec
6
+ task default: :spec
7
7
 
8
8
  task :console do
9
9
  require 'pry'
@@ -1,30 +1,37 @@
1
- # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
1
+ # coding: utf-8
2
+ $:.push File.expand_path('../lib', __FILE__)
4
3
  require 'ajax-datatables-rails/version'
5
4
 
6
- Gem::Specification.new do |gem|
7
- gem.name = "ajax-datatables-rails"
8
- gem.version = AjaxDatatablesRails::VERSION
9
- gem.authors = ["Joel Quenneville"]
10
- gem.email = ["joel.quenneville@collegeplus.org"]
11
- gem.description = %q{A gem that simplifies using datatables and hundreds of records via ajax}
12
- gem.summary = %q{A wrapper around datatable's ajax methods that allow synchronization with server-side pagination in a rails app}
13
- gem.homepage = ""
14
- gem.required_ruby_version = Gem::Requirement.new(">= 1.9.3")
5
+ Gem::Specification.new do |s|
6
+ s.name = 'ajax-datatables-rails'
7
+ s.version = AjaxDatatablesRails::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Joel Quenneville', 'Antonio Antillon']
10
+ s.email = ['joel.quenneville@collegeplus.org', 'antillas21@gmail.com']
11
+ s.homepage = 'https://github.com/jbox-web/ajax-datatables-rails'
12
+ s.summary = %q{A gem that simplifies using datatables and hundreds of records via ajax}
13
+ s.description = %q{A wrapper around datatable's ajax methods that allow synchronization with server-side pagination in a rails app}
14
+ s.license = 'MIT'
15
15
 
16
- gem.files = Dir["{lib,spec}/**/*", "[A-Z]*"] - ["Gemfile.lock"]
17
- gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
- gem.require_path = "lib"
16
+ s.add_dependency 'railties', '>= 4.0'
20
17
 
21
- gem.add_dependency 'railties', '>= 3.1'
18
+ s.add_development_dependency 'rails', '>= 4.0'
19
+ s.add_development_dependency 'rake'
20
+ s.add_development_dependency 'pg'
21
+ s.add_development_dependency 'mysql2'
22
+ s.add_development_dependency 'sqlite3'
23
+ s.add_development_dependency 'activerecord-oracle_enhanced-adapter'
24
+ s.add_development_dependency 'rspec'
25
+ s.add_development_dependency 'generator_spec'
26
+ s.add_development_dependency 'pry'
27
+ s.add_development_dependency 'simplecov'
28
+ s.add_development_dependency 'database_cleaner'
29
+ s.add_development_dependency 'factory_girl'
30
+ s.add_development_dependency 'faker'
31
+ s.add_development_dependency 'appraisal'
22
32
 
23
- gem.add_development_dependency "rspec"
24
- gem.add_development_dependency "generator_spec"
25
- gem.add_development_dependency "pry"
26
- gem.add_development_dependency "rake"
27
- gem.add_development_dependency "sqlite3"
28
- gem.add_development_dependency "rails", ">= 3.1.0"
29
- gem.add_development_dependency "activerecord", ">= 4.1.6"
33
+ s.files = `git ls-files`.split("\n")
34
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
35
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
36
+ s.require_paths = ['lib']
30
37
  end
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "4.0.13"
6
+ gem "mysql2", "~> 0.3.18"
7
+ gem "activerecord-oracle_enhanced-adapter", "~> 1.5.0"
8
+ gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
9
+
10
+ group :test do
11
+ gem "codeclimate-test-reporter", "~> 1.0.0"
12
+ end
13
+
14
+ gemspec path: "../"
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "4.1.15"
6
+ gem "mysql2", "~> 0.3.18"
7
+ gem "activerecord-oracle_enhanced-adapter", "~> 1.5.0"
8
+ gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
9
+
10
+ group :test do
11
+ gem "codeclimate-test-reporter", "~> 1.0.0"
12
+ end
13
+
14
+ gemspec path: "../"
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "4.2.8"
6
+ gem "activerecord-oracle_enhanced-adapter", "~> 1.6.0"
7
+ gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
8
+
9
+ group :test do
10
+ gem "codeclimate-test-reporter", "~> 1.0.0"
11
+ end
12
+
13
+ gemspec path: "../"
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "5.0.3"
6
+ gem "activerecord-oracle_enhanced-adapter", "~> 1.7.0"
7
+ gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
8
+
9
+ group :test do
10
+ gem "codeclimate-test-reporter", "~> 1.0.0"
11
+ end
12
+
13
+ gemspec path: "../"
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "5.1.1"
6
+ gem "activerecord-oracle_enhanced-adapter", "~> 1.8.0"
7
+ gem "ruby-oci8" if ENV["DB_ADAPTER"] == "oracle_enhanced"
8
+
9
+ group :test do
10
+ gem "codeclimate-test-reporter", "~> 1.0.0"
11
+ end
12
+
13
+ gemspec path: "../"
@@ -1,10 +1,11 @@
1
- require 'ajax-datatables-rails/version'
2
- require 'ajax-datatables-rails/config'
3
- require 'ajax-datatables-rails/models'
4
- require 'ajax-datatables-rails/base'
5
- require 'ajax-datatables-rails/extensions/simple_paginator'
6
- require 'ajax-datatables-rails/extensions/kaminari'
7
- require 'ajax-datatables-rails/extensions/will_paginate'
8
-
9
1
  module AjaxDatatablesRails
2
+ require 'ajax-datatables-rails/version'
3
+ require 'ajax-datatables-rails/config'
4
+ require 'ajax-datatables-rails/base'
5
+ require 'ajax-datatables-rails/datatable/datatable'
6
+ require 'ajax-datatables-rails/datatable/simple_search'
7
+ require 'ajax-datatables-rails/datatable/simple_order'
8
+ require 'ajax-datatables-rails/datatable/column_date_filter' unless AjaxDatatablesRails.old_rails?
9
+ require 'ajax-datatables-rails/datatable/column'
10
+ require 'ajax-datatables-rails/orm/active_record'
10
11
  end
@@ -1,214 +1,138 @@
1
1
  module AjaxDatatablesRails
2
+ class NotImplemented < StandardError; end
3
+
2
4
  class Base
3
5
  extend Forwardable
4
- class MethodNotImplementedError < StandardError; end
5
6
 
6
- attr_reader :view, :options, :sortable_columns, :searchable_columns
7
- def_delegator :@view, :params, :params
7
+ attr_reader :view, :options
8
+ def_delegator :@view, :params
8
9
 
9
10
  def initialize(view, options = {})
10
- @view = view
11
+ @view = view
11
12
  @options = options
12
- load_paginator
13
+ load_orm_extension
13
14
  end
14
15
 
15
16
  def config
16
17
  @config ||= AjaxDatatablesRails.config
17
18
  end
18
19
 
19
- def sortable_columns
20
- @sortable_columns ||= []
21
- end
22
-
23
- def searchable_columns
24
- @searchable_columns ||= []
20
+ def datatable
21
+ @datatable ||= Datatable::Datatable.new(self)
25
22
  end
26
23
 
27
- def data
28
- fail(
29
- MethodNotImplementedError,
30
- 'Please implement this method in your class.'
31
- )
24
+ def view_columns
25
+ fail(NotImplemented, view_columns_error_text)
32
26
  end
33
27
 
34
28
  def get_raw_records
35
- fail(
36
- MethodNotImplementedError,
37
- 'Please implement this method in your class.'
38
- )
29
+ fail(NotImplemented, raw_records_error_text)
39
30
  end
40
31
 
41
- def as_json(options = {})
42
- {
43
- :draw => params[:draw].to_i,
44
- :recordsTotal => get_raw_records.count(:all),
45
- :recordsFiltered => filter_records(get_raw_records).count(:all),
46
- :data => data
47
- }
32
+ def data
33
+ fail(NotImplemented, data_error_text)
48
34
  end
49
35
 
50
- def self.deprecated(message, caller = Kernel.caller[1])
51
- warning = caller + ": " + message
52
-
53
- if(respond_to?(:logger) && logger.present?)
54
- logger.warn(warning)
55
- else
56
- warn(warning)
57
- end
36
+ def additional_datas
37
+ {}
58
38
  end
59
39
 
60
- private
61
-
62
- def records
63
- @records ||= fetch_records
40
+ def as_json(*)
41
+ {
42
+ recordsTotal: records_total_count,
43
+ recordsFiltered: records_filtered_count,
44
+ data: sanitize(data)
45
+ }.merge(additional_datas)
64
46
  end
65
47
 
66
- def fetch_records
67
- records = get_raw_records
68
- records = sort_records(records) if params[:order].present?
69
- records = filter_records(records) if params[:search].present?
70
- records = paginate_records(records) unless params[:length].present? && params[:length] == '-1'
71
- records
48
+ def records
49
+ @records ||= retrieve_records
72
50
  end
73
51
 
74
- def sort_records(records)
75
- sort_by = []
76
- params[:order].each_value do |item|
77
- sort_by << "#{sort_column(item)} #{sort_direction(item)}"
52
+ # helper methods
53
+ def connected_columns
54
+ @connected_columns ||= begin
55
+ view_columns.keys.map do |field_name|
56
+ datatable.column_by(:data, field_name.to_s)
57
+ end.compact
78
58
  end
79
- records.order(sort_by.join(", "))
80
- end
81
-
82
- def paginate_records(records)
83
- fail(
84
- MethodNotImplementedError,
85
- 'Please mixin a pagination extension.'
86
- )
87
- end
88
-
89
- def filter_records(records)
90
- records = simple_search(records)
91
- records = composite_search(records)
92
- records
93
- end
94
-
95
- def simple_search(records)
96
- return records unless (params[:search].present? && params[:search][:value].present?)
97
- conditions = build_conditions_for(params[:search][:value])
98
- records = records.where(conditions) if conditions
99
- records
100
59
  end
101
60
 
102
- def composite_search(records)
103
- conditions = aggregate_query
104
- records = records.where(conditions) if conditions
105
- records
106
- end
107
-
108
- def build_conditions_for(query)
109
- search_for = query.split(' ')
110
- criteria = search_for.inject([]) do |criteria, atom|
111
- criteria << searchable_columns.map { |col| search_condition(col, atom) }.reduce(:or)
112
- end.reduce(:and)
113
- criteria
114
- end
115
-
116
- def search_condition(column, value)
117
- if column[0] == column.downcase[0]
118
- ::AjaxDatatablesRails::Base.deprecated '[DEPRECATED] Using table_name.column_name notation is deprecated. Please refer to: https://github.com/antillas21/ajax-datatables-rails#searchable-and-sortable-columns-syntax'
119
- return deprecated_search_condition(column, value)
120
- else
121
- return new_search_condition(column, value)
61
+ def searchable_columns
62
+ @searchable_columns ||= begin
63
+ connected_columns.select(&:searchable?)
122
64
  end
123
65
  end
124
66
 
125
- def new_search_condition(column, value)
126
- model, column = column.split('.')
127
- model = model.constantize
128
- casted_column = ::Arel::Nodes::NamedFunction.new('CAST', [model.arel_table[column.to_sym].as(typecast)])
129
- casted_column.matches("%#{value}%")
130
- end
131
-
132
- def deprecated_search_condition(column, value)
133
- model, column = column.split('.')
134
- model = model.singularize.titleize.gsub( / /, '' ).constantize
135
-
136
- casted_column = ::Arel::Nodes::NamedFunction.new('CAST', [model.arel_table[column.to_sym].as(typecast)])
137
- casted_column.matches("%#{value}%")
138
- end
139
-
140
- def aggregate_query
141
- conditions = searchable_columns.each_with_index.map do |column, index|
142
- value = params[:columns]["#{index}"][:search][:value] if params[:columns]
143
- search_condition(column, value) unless value.blank?
67
+ def search_columns
68
+ @search_columns ||= begin
69
+ searchable_columns.select(&:searched?)
144
70
  end
145
- conditions.compact.reduce(:and)
146
71
  end
147
72
 
148
- def typecast
149
- case config.db_adapter
150
- when :oracle then 'VARCHAR2(4000)'
151
- when :pg then 'VARCHAR'
152
- when :mysql2 then 'CHAR'
153
- when :sqlite3 then 'TEXT'
73
+ private
74
+
75
+ def sanitize(data)
76
+ data.map do |record|
77
+ if record.is_a?(Array)
78
+ record.map { |td| ERB::Util.html_escape(td) }
79
+ else
80
+ record.update(record){ |_, v| ERB::Util.html_escape(v) }
81
+ end
154
82
  end
155
83
  end
156
84
 
157
- def offset
158
- (page - 1) * per_page
85
+ def retrieve_records
86
+ records = fetch_records
87
+ records = filter_records(records)
88
+ records = sort_records(records) if datatable.orderable?
89
+ records = paginate_records(records) if datatable.paginate?
90
+ records
159
91
  end
160
92
 
161
- def page
162
- (params[:start].to_i / per_page) + 1
93
+ def records_total_count
94
+ get_raw_records.count(:all)
163
95
  end
164
96
 
165
- def per_page
166
- params.fetch(:length, 10).to_i
97
+ def records_filtered_count
98
+ filter_records(get_raw_records).count(:all)
167
99
  end
168
100
 
169
- def sort_column(item)
170
- new_sort_column(item)
171
- rescue
172
- ::AjaxDatatablesRails::Base.deprecated '[DEPRECATED] Using table_name.column_name notation is deprecated. Please refer to: https://github.com/antillas21/ajax-datatables-rails#searchable-and-sortable-columns-syntax'
173
- deprecated_sort_column(item)
101
+ # Private helper methods
102
+ def load_orm_extension
103
+ case config.orm
104
+ when :mongoid then nil
105
+ when :active_record then extend ORM::ActiveRecord
106
+ else
107
+ nil
108
+ end
174
109
  end
175
110
 
176
- def deprecated_sort_column(item)
177
- sortable_columns[sortable_displayed_columns.index(item[:column])]
178
- end
111
+ def raw_records_error_text
112
+ return <<-eos
179
113
 
180
- def new_sort_column(item)
181
- model, column = sortable_columns[sortable_displayed_columns.index(item[:column])].split('.')
182
- col = [model.constantize.table_name, column].join('.')
114
+ You should implement this method in your class and specify
115
+ how records are going to be retrieved from the database.
116
+ eos
183
117
  end
184
118
 
185
- def sort_direction(item)
186
- options = %w(desc asc)
187
- options.include?(item[:dir]) ? item[:dir].upcase : 'ASC'
188
- end
119
+ def data_error_text
120
+ return <<-eos
189
121
 
190
- def sortable_displayed_columns
191
- @sortable_displayed_columns ||= generate_sortable_displayed_columns
122
+ You should implement this method in your class and return an array
123
+ of arrays, or an array of hashes, as defined in the jQuery.dataTables
124
+ plugin documentation.
125
+ eos
192
126
  end
193
127
 
194
- def generate_sortable_displayed_columns
195
- @sortable_displayed_columns = []
196
- params[:columns].each_value do |column|
197
- @sortable_displayed_columns << column[:data] if column[:orderable] == 'true'
198
- end
199
- @sortable_displayed_columns
200
- end
128
+ def view_columns_error_text
129
+ return <<-eos
201
130
 
202
- def load_paginator
203
- case config.paginator
204
- when :kaminari
205
- extend Extensions::Kaminari
206
- when :will_paginate
207
- extend Extensions::WillPaginate
208
- else
209
- extend Extensions::SimplePaginator
210
- end
211
- self
131
+ You should implement this method in your class and return an array
132
+ of database columns based on the columns displayed in the HTML view.
133
+ These columns should be represented in the ModelName.column_name,
134
+ or aliased_join_table.column_name notation.
135
+ eos
212
136
  end
213
137
  end
214
138
  end