data_tables 0.1.7 → 0.1.9

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.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ rdoc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format doc
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+
5
+
6
+ group :development, :test do
7
+ gem 'rspec'
8
+ gem 'guard-rspec'
9
+ gem 'rb-inotify', '~> 0.9'
10
+ gem 'tire'
11
+ gem 'ohm'
12
+ gem 'activerecord'
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,90 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ data_tables (0.1.9)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (3.2.12)
10
+ activesupport (= 3.2.12)
11
+ builder (~> 3.0.0)
12
+ activerecord (3.2.12)
13
+ activemodel (= 3.2.12)
14
+ activesupport (= 3.2.12)
15
+ arel (~> 3.0.2)
16
+ tzinfo (~> 0.3.29)
17
+ activesupport (3.2.12)
18
+ i18n (~> 0.6)
19
+ multi_json (~> 1.0)
20
+ ansi (1.4.3)
21
+ arel (3.0.2)
22
+ builder (3.0.4)
23
+ coderay (1.0.9)
24
+ diff-lcs (1.2.1)
25
+ ffi (1.7.0)
26
+ formatador (0.2.4)
27
+ guard (1.7.0)
28
+ formatador (>= 0.2.4)
29
+ listen (>= 0.6.0)
30
+ lumberjack (>= 1.0.2)
31
+ pry (>= 0.9.10)
32
+ thor (>= 0.14.6)
33
+ guard-rspec (2.5.3)
34
+ guard (>= 1.1)
35
+ rspec (~> 2.11)
36
+ hashr (0.0.22)
37
+ i18n (0.6.1)
38
+ listen (0.7.3)
39
+ lumberjack (1.0.3)
40
+ method_source (0.8.1)
41
+ mime-types (1.22)
42
+ multi_json (1.6.1)
43
+ nest (1.1.2)
44
+ redis
45
+ ohm (1.3.1)
46
+ nest (~> 1.0)
47
+ redis
48
+ scrivener (~> 0.0.3)
49
+ pry (0.9.12)
50
+ coderay (~> 1.0.5)
51
+ method_source (~> 0.8)
52
+ slop (~> 3.4)
53
+ rake (10.0.4)
54
+ rb-inotify (0.9.0)
55
+ ffi (>= 0.5.0)
56
+ redis (3.0.3)
57
+ rest-client (1.6.7)
58
+ mime-types (>= 1.16)
59
+ rspec (2.13.0)
60
+ rspec-core (~> 2.13.0)
61
+ rspec-expectations (~> 2.13.0)
62
+ rspec-mocks (~> 2.13.0)
63
+ rspec-core (2.13.1)
64
+ rspec-expectations (2.13.0)
65
+ diff-lcs (>= 1.1.3, < 2.0)
66
+ rspec-mocks (2.13.0)
67
+ scrivener (0.0.3)
68
+ slop (3.4.4)
69
+ thor (0.18.1)
70
+ tire (0.5.7)
71
+ activemodel (>= 3.0)
72
+ activesupport
73
+ ansi
74
+ hashr (~> 0.0.19)
75
+ multi_json (~> 1.3)
76
+ rake
77
+ rest-client (~> 1.6)
78
+ tzinfo (0.3.37)
79
+
80
+ PLATFORMS
81
+ ruby
82
+
83
+ DEPENDENCIES
84
+ activerecord
85
+ data_tables!
86
+ guard-rspec
87
+ ohm
88
+ rb-inotify (~> 0.9)
89
+ rspec
90
+ tire
data/Guardfile ADDED
@@ -0,0 +1,25 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ watch(%r{spec/models/(.+)\.rb$}) { "spec" }
9
+
10
+ # Rails example
11
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
12
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
13
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
14
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
15
+ watch('config/routes.rb') { "spec/routing" }
16
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
17
+
18
+ # Capybara features specs
19
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
20
+
21
+ # Turnip features and steps
22
+ watch(%r{^spec/acceptance/(.+)\.feature$})
23
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
24
+ end
25
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,89 @@
1
+ Datatables
2
+ ==========
3
+
4
+ Rails plugin for adding JQuery DataTables to your application.
5
+
6
+ DataTables: http://datatables.net/index
7
+
8
+ Requirements:
9
+
10
+ JQuery, JQuery UI, and the DataTables JQuery plugin
11
+
12
+ For Ohm Support:
13
+ redis, Ohm, Lunar
14
+
15
+ Features:
16
+
17
+ Easy definition of a table for an ActiveRecord and Ohm model.
18
+ Supports pagination.
19
+
20
+
21
+ TODO
22
+ =======
23
+
24
+ Add tests.
25
+ Add sorting.
26
+
27
+
28
+ Example
29
+ =======
30
+
31
+ In your controller, set up a datatables source. This is how the data is pulled from the server and returned with AJAX.
32
+
33
+ Initializer
34
+ ============
35
+ ActionView::Base.send :include, DataTablesHelper
36
+ ActionController::Base.send :include, DataTablesController
37
+
38
+ Controller
39
+ ===========
40
+
41
+ datatables_source :users_source, :user, :columns => [
42
+ :username, :fullname, {:name => "updated_at", :eval => 'obj.updated_at.getlocal.rfc2822'},
43
+ {:name => "Options", :method => :user_options_column}], :numResults => 10
44
+
45
+ This defines a table, named users_source, for the User model.
46
+
47
+ The columns are (in order):
48
+
49
+ username, fullname, updated_at, and options
50
+
51
+ There are two special ways to display the data for a column/row.
52
+
53
+ eval:
54
+
55
+ Evaluates a string, "obj" is an instance of your model in the table (in this case, a User object).
56
+
57
+
58
+ method:
59
+
60
+ Calls a method in your controller with the instance of your model as the parameter.
61
+
62
+ When defining a method for a column, an example method in your controller would be:
63
+
64
+ def user_options_column(user)
65
+ "<a href=\"#{url_for :action => 'view', :id => user.id}\">View User</a>"
66
+ end
67
+
68
+
69
+ Routes
70
+ =========
71
+
72
+ Because DataTables uses AJAX to load the data in the table, you must define a route to it. The first parameter of datatables_source is a *named route*. The rails plugin uses this to link the HTML for your DataTable.
73
+
74
+ Example
75
+ =========
76
+
77
+ map.users_source '/datatables/user', :controller => :user, :action => :users_source
78
+
79
+
80
+ Displaying the table
81
+ =========================
82
+
83
+ Displaying a table is probably the easiest part. In a view for your controller, you just do the following:
84
+
85
+ <%= datatables :users_source %>
86
+
87
+
88
+ Copyright (c) 2010 Chris Moos, released under the MIT license
89
+ Copyright (c) 2012 Duane Compton, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the datatables plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the datatables plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Datatables'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'data_tables'
5
+ s.version = '0.1.9'
6
+ s.date = Time.now.strftime("%Y-%m-%d")
7
+ s.summary = "Rails friendly interface into DataTables"
8
+ s.description = "DataTables for Rails"
9
+ s.authors = ["Duane Compton", "Calvin Bascom", "Yi Su", "Chris Moos", "Adrian Mejia"]
10
+ s.email = 'Duane.Compton@gmail.com'
11
+ s.homepage = 'http://rubygems.org/gems/data_tables'
12
+ s.platform = Gem::Platform::RUBY
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_development_dependency 'rspec', '~> 2.10'
19
+ end
20
+
data/lib/data_tables.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "data_tables/data_tables_helper"
2
+
2
3
  module DataTablesController
3
4
  def self.included(cls)
4
5
  cls.extend(ClassMethods)
@@ -44,38 +45,103 @@ module DataTablesController
44
45
  named_scope = options[:named_scope]
45
46
  named_scope_args = options[:named_scope_args]
46
47
  except = options[:except]
48
+ es_block = options[:es_block]
47
49
 
50
+ #
51
+ # ------- Ohm ----------- #
52
+ #
48
53
  if modelCls < Ohm::Model
49
54
  define_method action.to_sym do
55
+ logger.debug "[tire] (datatable:#{__LINE__}) #{action.to_sym} #{modelCls} < Ohm::Model"
56
+
50
57
  if scope == :domain
51
58
  domain = ActiveRecord::Base.connection.schema_search_path.to_s.split(",")[0]
52
59
  return if domain.nil?
53
60
  end
54
61
  search_condition = params[:sSearch].blank? ? nil : params[:sSearch].to_s
55
- records = scope == :domain ? modelCls.find(:domain => domain) : modelCls.all
56
- if except
57
- except.each do |f|
58
- records = records.except(f[0].to_sym => f[1])
59
- end
60
- end
61
- total_records = records.size
62
+
62
63
  sort_column = params[:iSortCol_0].to_i
63
64
  sort_column = 1 if sort_column == 0
64
65
  current_page = (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i rescue 0) + 1
65
- objects = nil
66
- if search_condition.nil?
67
- if Gem.loaded_specs['ohm'].version == Gem::Version.create('0.1.5')
68
- objects = records.sort_by(columns[sort_column][:name].to_sym,
69
- :order => "ALPHA " + params[:sSortDir_0].capitalize,
70
- :start => params[:iDisplayStart].to_i,
71
- :limit => params[:iDisplayLength].to_i)
66
+ per_page = params[:iDisplayLength] || 10
67
+ per_page = per_page.to_i
68
+ sort_dir = params[:sSortDir_0] || 'desc'
69
+ column_name_sym = columns[sort_column][:name].to_sym
70
+
71
+ objects = []
72
+ total_display_records = 0
73
+ total_records = 0
74
+
75
+ if defined? Tire
76
+ #
77
+ # ----------- Elasticsearch/Tire for Ohm ----------- #
78
+ #
79
+ elastic_index_name = "#{Tire::Model::Search.index_prefix}#{modelCls.to_s.underscore}"
80
+ logger.debug "*** (datatable:#{__LINE__}) Using tire for search #{modelCls} (#{elastic_index_name})"
81
+
82
+ search_condition = elasticsearch_sanitation(search_condition, except)
83
+ just_excepts = except ? elasticsearch_sanitation(nil, except) : "*"
84
+ logger.debug "*** search_condition = #{search_condition}; sort by #{column_name_sym}:#{sort_dir}; domain=`#{domain.inspect}'"
85
+
86
+ retried = 0
87
+ if Tire.index(elastic_index_name){exists?}.response.code != 404
88
+ begin
89
+ controller_instance = self
90
+ results = Tire.search(elastic_index_name) do
91
+ # retry #2 exclude search terms (and sorting) from search query
92
+ if retried < 2
93
+ query { string search_condition }
94
+ else
95
+ query { string just_excepts }
96
+ end
97
+
98
+ # retry #1 exclude sorting from search query
99
+ sort{ by column_name_sym, sort_dir } if retried < 1
100
+
101
+ filter(:term, domain: domain) unless domain.blank?
102
+ if es_block.is_a?(Symbol)
103
+ controller_instance.send(es_block, self)
104
+ else
105
+ es_block.call(self) if es_block.respond_to?(:call)
106
+ end
107
+ from (current_page-1) * per_page
108
+ size per_page
109
+ end.results
110
+
111
+ objects = results.map{ |r| modelCls[r._id] }.compact
112
+ total_display_records = results.total
113
+
114
+
115
+ total_records = Tire.search(elastic_index_name, search_type: 'count') do
116
+ query { string just_excepts }
117
+ filter(:term, domain: domain) unless domain.blank?
118
+ es_block.call(self) if es_block.respond_to?(:call)
119
+ end.results.total
120
+ rescue Tire::Search::SearchRequestFailed => e
121
+ if retried < 2
122
+ retried += 1
123
+ logger.info "Will retry(#{retried}) again because #{e.inspect}"
124
+ retry
125
+ end
126
+ logger.info "*** ERROR: Tire::Search::SearchRequestFailed => #{e.inspect}"
127
+ end
72
128
  else
73
- objects = records.sort_by(columns[sort_column][:name].to_sym,
74
- :order => "ALPHA " + params[:sSortDir_0].capitalize,
75
- :limit => [params[:iDisplayStart].to_i, params[:iDisplayLength].to_i])
129
+ logger.debug "Index #{elastic_index_name} does not exists yet in ES."
76
130
  end
77
- total_display_records = total_records
78
131
  else
132
+ #
133
+ # -------- Redis/Lunar search --------------- #
134
+ #
135
+ logger.debug "*** (datatable:#{__LINE__}) Using Redis/Lunar for search #{modelCls} (#{elastic_index_name})"
136
+ records = scope == :domain ? modelCls.find(:domain => domain) : modelCls.all
137
+ if except
138
+ except.each do |f|
139
+ records = records.except(f[0].to_sym => f[1])
140
+ end
141
+ end
142
+ total_records = records.size
143
+
144
+ logger.debug "*** (datatable:#{__LINE__}) NOT using tire for search"
79
145
  options = {}
80
146
  domain_id = domain.split("_")[1].to_i if scope == :domain
81
147
  options[:domain] = domain_id .. domain_id if scope == :domain
@@ -92,7 +158,9 @@ module DataTablesController
92
158
  :order => "ALPHA " + params[:sSortDir_0].capitalize,
93
159
  :limit => [params[:iDisplayStart].to_i, params[:iDisplayLength].to_i])
94
160
  end
161
+ # -------- Redis/Lunar search --------------- #
95
162
  end
163
+
96
164
  data = objects.collect do |instance|
97
165
  columns.collect { |column| datatables_instance_get_value(instance, column) }
98
166
  end
@@ -101,74 +169,150 @@ module DataTablesController
101
169
  :aaData => data,
102
170
  :sEcho => params[:sEcho].to_i}.to_json
103
171
  end
104
- else
172
+ # ------- /Ohm ----------- #
173
+ else # Non-ohm models
105
174
  # add_search_option will determine whether the search text is empty or not
106
175
  init_conditions = conditions.clone
107
176
  add_search_option = false
108
- define_method action.to_sym do
109
- condition_local = ''
110
- unless params[:sSearch].blank?
111
- sort_column_id = params[:iSortCol_0].to_i
112
- sort_column_id = 1 if sort_column_id == 0
113
- sort_column = columns[sort_column_id]
114
- if sort_column && sort_column.has_key?(:attribute)
115
- condstr = params[:sSearch].gsub(/_/, '\\\\_').gsub(/%/, '\\\\%')
116
- condition_local = "(text(#{sort_column[:name]}) ILIKE '#{condstr}%')"
177
+
178
+ if modelCls.ancestors.any?{|ancestor| ancestor.name == "Tire::Model::Search"}
179
+ #
180
+ # ------- Elasticsearch ----------- #
181
+ #
182
+ define_method action.to_sym do
183
+ domain_name = ActiveRecord::Base.connection.schema_search_path.to_s.split(",")[0]
184
+ logger.debug "*** Using ElasticSearch for #{modelCls.name}"
185
+ objects = []
186
+
187
+ condstr = ""
188
+ unless params[:sSearch].blank?
189
+ sort_column_id = params[:iSortCol_0].to_i
190
+ sort_column_id = 1 if sort_column_id == 0
191
+ sort_column = columns[sort_column_id]
192
+ if sort_column && sort_column.has_key?(:attribute)
193
+ condstr = params[:sSearch].gsub(/_/, '\\\\_').gsub(/%/, '\\\\%')
194
+ end
195
+ end
196
+
197
+ sort_column = params[:iSortCol_0].to_i
198
+ current_page = (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i rescue 0)+1
199
+ per_page = params[:iDisplayLength] || 10
200
+ column_name = columns[sort_column][:name] || 'message'
201
+ sort_dir = params[:sSortDir_0] || 'desc'
202
+
203
+ condstr = elasticsearch_sanitation(condstr, except)
204
+
205
+ begin
206
+ query = Proc.new do
207
+ query { string(condstr) }
208
+ filter(:term, domain: domain_name) unless domain_name.blank?
209
+ es_block.call(self) if es_block.respond_to?(:call)
210
+ end
211
+
212
+ results = modelCls.search(page: current_page,
213
+ per_page: per_page,
214
+ sort: "#{column_name}:#{sort_dir}",
215
+ &query)
216
+ objects = results.to_a
217
+ total_display_records = results.total
218
+ total_records = modelCls.search(search_type: 'count') do
219
+ filter(:term, domain: domain_name) unless domain_name.blank?
220
+ es_block.call(self) if es_block.respond_to?(:call)
221
+ end.total
222
+ rescue Tire::Search::SearchRequestFailed => e
223
+ logger.debug "[Tire::Search::SearchRequestFailed] #{e.inspect}\n#{e.backtrace.join("\n")}"
224
+ objects = []
225
+ total_display_records = 0
226
+ total_records = 0
117
227
  end
228
+
229
+ data = objects.collect do |instance|
230
+ columns.collect { |column| datatables_instance_get_value(instance, column) }
231
+ end
232
+
233
+ render :text => {:iTotalRecords => total_records,
234
+ :iTotalDisplayRecords => total_display_records,
235
+ :aaData => data,
236
+ :sEcho => params[:sEcho].to_i}.to_json
118
237
  end
238
+ # ------- /Elasticsearch ----------- #
239
+ else
240
+ #
241
+ # ------- Postgres ----------- #
242
+ #
243
+ logger.debug "(datatable) #{action.to_sym} #{modelCls} < ActiveRecord"
119
244
 
120
- # We just need one conditions string for search at a time. Every time we input
121
- # something else in the search bar we will pop the previous search condition
122
- # string and push the new string.
123
- if condition_local != ''
124
- if add_search_option == false
125
- conditions << condition_local
126
- add_search_option = true
127
- else
128
- if conditions != []
129
- conditions.pop
245
+ define_method action.to_sym do
246
+ condition_local = ''
247
+ unless params[:sSearch].blank?
248
+ sort_column_id = params[:iSortCol_0].to_i
249
+ sort_column_id = 1 if sort_column_id == 0
250
+ sort_column = columns[sort_column_id]
251
+ condstr = params[:sSearch].strip.gsub(/_/, '\\\\_').gsub(/%/, '\\\\%')
252
+
253
+ search_columns = options[:columns].map{|e| e.class == Symbol ? e : nil }.compact
254
+ condition_local = search_columns.map do |column_name|
255
+ " ((text(#{column_name}) ILIKE '%#{condstr}%')) "
256
+ end.compact.join(" OR ")
257
+ condition_local = " ( #{condition_local} ) " unless condition_local.blank?
258
+ end
259
+
260
+ # We just need one conditions string for search at a time. Every time we input
261
+ # something else in the search bar we will pop the previous search condition
262
+ # string and push the new string.
263
+ if condition_local != ''
264
+ if add_search_option == false
130
265
  conditions << condition_local
266
+ add_search_option = true
267
+ else
268
+ if conditions != []
269
+ conditions.pop
270
+ conditions << condition_local
271
+ end
131
272
  end
132
- end
133
- else
134
- if add_search_option == true
135
- if conditions != []
136
- conditions.pop
137
- add_search_option = false
273
+ else
274
+ if add_search_option == true
275
+ if conditions != []
276
+ conditions.pop
277
+ add_search_option = false
278
+ end
138
279
  end
139
280
  end
140
- end
141
281
 
142
- if named_scope
143
- args = named_scope_args ? Array(self.send(named_scope_args)) : []
144
- total_records = modelCls.send(named_scope, *args).count :conditions => init_conditions.join(" AND ")
145
- total_display_records = modelCls.send(named_scope, *args).count :conditions => conditions.join(" AND ")
146
- else
147
- total_records = modelCls.count :conditions => init_conditions.join(" AND ")
148
- total_display_records = modelCls.count :conditions => conditions.join(" AND ")
149
- end
150
- sort_column = params[:iSortCol_0].to_i
151
- sort_column = 1 if sort_column == 0
152
- current_page = (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i rescue 0)+1
153
- if named_scope
154
- objects = modelCls.send(named_scope, *args).paginate(:page => current_page,
155
- :order => "#{columns[sort_column][:name]} #{params[:sSortDir_0]}",
156
- :conditions => conditions.join(" AND "),
157
- :per_page => params[:iDisplayLength])
158
- else
159
- objects = modelCls.paginate(:page => current_page,
160
- :order => "#{columns[sort_column][:name]} #{params[:sSortDir_0]}",
161
- :conditions => conditions.join(" AND "),
162
- :per_page => params[:iDisplayLength])
163
- end
164
- #logger.info("------conditions is #{conditions}")
165
- data = objects.collect do |instance|
166
- columns.collect { |column| datatables_instance_get_value(instance, column) }
282
+ if named_scope
283
+ args = named_scope_args ? Array(self.send(named_scope_args)) : []
284
+ total_records = modelCls.send(named_scope, *args).count :conditions => init_conditions.join(" AND ")
285
+ total_display_records = modelCls.send(named_scope, *args).count :conditions => conditions.join(" AND ")
286
+ else
287
+ total_records = modelCls.count :conditions => init_conditions.join(" AND ")
288
+ total_display_records = modelCls.count :conditions => conditions.join(" AND ")
289
+ end
290
+ sort_column = params[:iSortCol_0].to_i
291
+ sort_column = 1 if sort_column == 0
292
+ current_page = (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i rescue 0)+1
293
+ if named_scope
294
+ objects = modelCls.send(named_scope, *args).paginate(:page => current_page,
295
+ :order => "#{columns[sort_column][:name]} #{params[:sSortDir_0]}",
296
+ :conditions => conditions.join(" AND "),
297
+ :per_page => params[:iDisplayLength])
298
+ else
299
+ objects = modelCls.paginate(:page => current_page,
300
+ :order => "#{columns[sort_column][:name]} #{params[:sSortDir_0]}",
301
+ :conditions => conditions.join(" AND "),
302
+ :per_page => params[:iDisplayLength])
303
+ end
304
+ #logger.info("------conditions is #{conditions}")
305
+ data = objects.collect do |instance|
306
+ columns.collect { |column| datatables_instance_get_value(instance, column) }
307
+ end
308
+ render :text => {:iTotalRecords => total_records,
309
+ :iTotalDisplayRecords => total_display_records,
310
+ :aaData => data,
311
+ :sEcho => params[:sEcho].to_i}.to_json
312
+ #
313
+ # ------- /Postgres ----------- #
314
+ #
167
315
  end
168
- render :text => {:iTotalRecords => total_records,
169
- :iTotalDisplayRecords => total_display_records,
170
- :aaData => data,
171
- :sEcho => params[:sEcho].to_i}.to_json
172
316
  end
173
317
  end
174
318
  end
@@ -184,7 +328,7 @@ module DataTablesController
184
328
  if column.kind_of? Symbol # a column from the database, we don't need to do anything
185
329
  columns << {:name => column, :attribute => column}
186
330
  elsif column.kind_of? Hash
187
- col_hash = { :name => column[:name], :special => column }
331
+ col_hash = { :name => column[:name], :special => column }
188
332
  col_hash[:attribute] = column[:attribute] if column[:attribute]
189
333
  columns << col_hash
190
334
  end
@@ -211,6 +355,18 @@ module DataTablesController
211
355
  end
212
356
  end
213
357
 
358
+ def elasticsearch_sanitation(search_string, except)
359
+ logger.debug "*** elasticsearch_sanitation.before = `#{search_string}'"
360
+ search_string = '*' if search_string.blank?
361
+ search_string.strip!
362
+ numerical_search = (search_string.split.count > 1) ? "" : "OR *#{search_string.gsub(":","\\:")}*"
363
+ search_string = "(\"*#{search_string}*\" #{numerical_search}) " unless search_string =~ /(\*|\")/
364
+ exceptions = except.map { |f| "NOT #{f[0]}:\"#{f[1]}\""}.join(" AND ") if except
365
+ search_string += " AND " + exceptions if exceptions
366
+ logger.debug "*** elasticsearch_sanitation.after = `#{search_string}'"
367
+ search_string
368
+ end
369
+
214
370
  # gets the value for a column and row
215
371
  def datatables_instance_get_value(instance, column)
216
372
  if column[:special]
@@ -8,24 +8,33 @@ module DataTablesHelper
8
8
  options[:bAutoWidth] = false unless options.has_key?(:bAutoWidth)
9
9
  options[:bStateSave] = true unless options.has_key?(:bStateSave)
10
10
  options[:oColVis] ||= {}
11
+ options[:bFilter] = true
11
12
  options[:oColVis][:aiExclude] ||= []
12
13
  unless options[:oColVis][:aiExclude].include?(0)
13
14
  options[:oColVis][:aiExclude].unshift(0)
14
15
  end
15
16
 
17
+ options[:bFilter] = opts[:search] unless opts[:search].nil?
18
+
16
19
  options[:fnInitComplete] ||= "function() {
17
20
  if (eval('typeof ' + initDatatablesTable) == 'function') {
18
21
  initDatatablesTable('#{source}');
19
22
  }
20
23
  }"
21
24
 
22
- sdom = '<"#datatables_search_hint">lfrtip'
25
+ sdom = options[:bFilter] ? '<"#datatables_search_hint">lfrtip' : 'lrtip'
23
26
  sdom = "C<\"clear\">" + sdom if options[:oColVis]
24
27
  sdom = 'T' + sdom if options[:oTableTools]
25
28
  options[:sDom] ||= sdom
26
29
 
30
+ # Rails.logger.info("*****#{options.inspect}")
31
+
32
+ # options[:sDom].delete(:f)
33
+
27
34
  datatable = controller.datatable_source(source)
28
- options[:sAjaxSource] = method("#{datatable[:action]}_url".to_sym).call
35
+ url_query_params = opts[:urlQueryParams] || {}
36
+ options[:sAjaxSource] = opts[:sAjaxSource] ||
37
+ method("#{datatable[:action]}_url".to_sym).call(url_query_params)
29
38
  columns = datatable[:attrs].keys.collect { |a| "<th>#{a}</th>" }.join
30
39
 
31
40
  index = 0
@@ -36,7 +45,7 @@ module DataTablesHelper
36
45
  index += 1
37
46
  memo
38
47
  end
39
- options[:aaSorting] = [[first_searchable_column_index, 'asc']]
48
+ options[:aaSorting] ||= [[first_searchable_column_index, 'asc']]
40
49
  options[:aoColumnDefs] ||= []
41
50
  options[:aoColumnDefs].unshift({
42
51
  :aTargets => targets,
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'data_tables' do
4
+ before :each do
5
+ if DEBUG
6
+ ExceptOptionController.any_instance.stub_chain(:logger, :debug){ |*args| puts args.first }
7
+ ExceptOptionController.any_instance.stub_chain(:logger, :info){ |*args| puts args.first }
8
+ else
9
+ ExceptOptionController.any_instance.stub(:logger).and_return(double("Logger").as_null_object)
10
+ end
11
+ ExceptOptionController.any_instance.stub(:params).and_return({})
12
+ ExceptOptionController.any_instance.stub(:render)
13
+ ActiveRecord::Base.stub_chain(:connection, :schema_search_path).and_return("public")
14
+ end
15
+
16
+ def save_elasticsearch(index_name, data)
17
+ Tire.index(index_name) do
18
+ create unless exists?
19
+ data.each do |datum|
20
+ store datum
21
+ end
22
+ refresh
23
+ end
24
+ end
25
+
26
+ let(:instance){ExceptOptionController.new.dummy_class_source}
27
+ let(:index_name){ "#{Tire::Model::Search.index_prefix}dummy_class" }
28
+
29
+ context "Redis Models" do
30
+ context "with ElasticSearch" do
31
+ {"iTotalDisplayRecords" => 2, "iTotalRecords" => 2}.each do |k,v|
32
+ it "respects datatables' except to calculate #{k} (#{v})" do
33
+ # create index
34
+ data = [{ id: 5002, name: 'not_valid', domain: 'public' },
35
+ { id: 561, name: 'Native AP VLAN', domain: 'public' },
36
+ { id: 56, name: 'valid', domain: 'public' }]
37
+ save_elasticsearch(index_name, data)
38
+
39
+ ExceptOptionController.any_instance.should_receive(:render) do |*args|
40
+ arg = JSON.parse(args.first[:text])
41
+ arg[k].should == v
42
+ end
43
+ instance
44
+ end
45
+ end
46
+ end
47
+ end
48
+ context "Elastic Search Models" do
49
+ end
50
+ context "Postgres Models" do
51
+ end
52
+ end
@@ -0,0 +1,25 @@
1
+ class DummyClass < Ohm::Model
2
+ end
3
+
4
+ class ConditionModel
5
+ include DataTablesController
6
+ datatables_source(:dummy_class_source, :dummy_class,
7
+ :columns => [
8
+ {:name => "Actions",
9
+ :method => :datatables_actions_column},
10
+ :name, :vlan, :cidr
11
+ ],
12
+ :conditions => ['id!=5002',"name!= 'Native AP VLAN'"])
13
+ end
14
+
15
+ class ExceptOptionController
16
+ include DataTablesController
17
+ datatables_source(:dummy_class_source, :dummy_class,
18
+ :columns => [
19
+ {:name => "Actions",
20
+ :method => :datatables_actions_column},
21
+ :name, :state, :cidr, :vlan,
22
+ {:name =>"Access Points",
23
+ :method => :location_statuses_accesspoint_list}
24
+ ],:except => [['name','Native AP VLAN']])
25
+ end
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'ohm'
4
+ require 'tire'
5
+ require 'active_record'
6
+
7
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__) + '/..'))
8
+ Dir[File.join(APP_ROOT, "lib/*.rb")].each {|f| require f}
9
+ Dir[File.join(APP_ROOT, "lib/data_tables/*.rb")].each {|f| require f}
10
+ Dir[File.join(APP_ROOT, "spec/models/*.rb")].each {|f| require f}
11
+
12
+ DEBUG = false
13
+
14
+ Tire.configure { logger STDOUT } if DEBUG
15
+ Tire::Model::Search.index_prefix('test_datatable_')
16
+
17
+ RSpec.configure do |config|
18
+ config.before(:each) do
19
+ Tire.index("#{Tire::Model::Search.index_prefix}*"){delete}
20
+ end
21
+ config.after(:each) do
22
+ #Tire.index("#{Tire::Model::Search.index_prefix}*"){delete}
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :datatables do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class DatatablesTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_support/test_case'
metadata CHANGED
@@ -2,26 +2,58 @@
2
2
  name: data_tables
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.7
5
+ version: 0.1.9
6
6
  platform: ruby
7
7
  authors:
8
8
  - Duane Compton
9
9
  - Calvin Bascom
10
10
  - Yi Su
11
11
  - Chris Moos
12
+ - Adrian Mejia
12
13
  autorequire:
13
14
  bindir: bin
14
15
  cert_chain: []
15
- date: 2012-10-10 00:00:00.000000000 Z
16
- dependencies: []
17
- description: Originally a plugin
16
+ date: 2013-07-03 00:00:00.000000000 Z
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ type: :development
20
+ name: rspec
21
+ prerelease: false
22
+ requirement: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.10'
27
+ none: false
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.10'
33
+ none: false
34
+ description: DataTables for Rails
18
35
  email: Duane.Compton@gmail.com
19
36
  executables: []
20
37
  extensions: []
21
38
  extra_rdoc_files: []
22
39
  files:
40
+ - .gitignore
41
+ - .rspec
42
+ - Gemfile
43
+ - Gemfile.lock
44
+ - Guardfile
45
+ - MIT-LICENSE
46
+ - README
47
+ - Rakefile
48
+ - data_tables.gemspec
23
49
  - lib/data_tables.rb
24
50
  - lib/data_tables/data_tables_helper.rb
51
+ - spec/data_tables_spec.rb
52
+ - spec/models/condition_model.rb
53
+ - spec/spec_helper.rb
54
+ - tasks/datatables_tasks.rake
55
+ - test/datatables_test.rb
56
+ - test/test_helper.rb
25
57
  homepage: http://rubygems.org/gems/data_tables
26
58
  licenses: []
27
59
  post_install_message:
@@ -46,4 +78,9 @@ rubygems_version: 1.8.24
46
78
  signing_key:
47
79
  specification_version: 3
48
80
  summary: Rails friendly interface into DataTables
49
- test_files: []
81
+ test_files:
82
+ - spec/data_tables_spec.rb
83
+ - spec/models/condition_model.rb
84
+ - spec/spec_helper.rb
85
+ - test/datatables_test.rb
86
+ - test/test_helper.rb