data_tables 0.1.7 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
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