tabulatr2 0.9.19 → 0.9.20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a3b655c03dcf50a82e78181d23282b2c0c8d31fe
4
- data.tar.gz: 1daac9cd6c31ed0d526179e20780916fbc1709be
3
+ metadata.gz: 8628bfd7be6d2d9e801984acaeef9057dd98aa24
4
+ data.tar.gz: 07d356b31c00175e286fdb09d84681ec71a41492
5
5
  SHA512:
6
- metadata.gz: 07c7126020999c9f651d2175dd5ec39551eec36b512171179b16cd4df4a0acfa3ea92bbb4ab34cd9cab4bd408802a2fca572044b49bf1653c1a396ff491e7a26
7
- data.tar.gz: 09f281504e5977518598b273656f022ba624e4556801c2261862bc16b031b204734f27db727bc8e2855f396ddedb39808e08fd91350d459e4b1ed5908a28b49f
6
+ metadata.gz: 7c313558231faee3dbbe107378401c04e517aba77caafd879b03f2104ef77dcdc7df50516fe01e078f801f3ad158185f8a8603bde668cb41f308b926de5b9d04
7
+ data.tar.gz: e4835fbbb8ed8be42acf6ffde94deb2d3b8e8ba0e4e2948c4ef15002a0fa2534a9f560570c3f753a822def719e35b2b82bcaddd8a3eeb7d1160369bc0d24a49e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## 0.9.20
2
+ * Add `filter` to DSL to define custom filters
3
+
4
+ Example:
5
+ ```
6
+ filter :product_price_range do |relation, value|
7
+ relation = relation.joins(:products)
8
+ if value == 'low'
9
+ relation.group("vendors.id").having('AVG(products.price) <= 100')
10
+ elsif value == 'high'
11
+ relation.group("vendors.id").having('AVG(products.price) > 100')
12
+ end
13
+ end
14
+ ```
15
+ * Add `current_user` local to Tabulatr::Data by default if available
16
+ and not already present
17
+
1
18
  ## 0.9.17
2
19
  * If a batch action is executed without checking any rows it
3
20
  will be applied to all rows in the current filter
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ gemspec
4
4
 
5
5
  gem 'jquery-rails'
6
6
 
7
- group :development do
7
+ group :development, :test do
8
8
  gem 'better_errors'
9
9
  gem 'binding_of_caller', platforms: :ruby
10
10
  end
data/README.md CHANGED
@@ -184,6 +184,44 @@ class UserTabulatrData < Tabulatr::Data
184
184
  end
185
185
  ```
186
186
 
187
+ ### Custom filters
188
+
189
+ You're also able to create custom filters with the `filter` method to create more advanced
190
+ filters which are independent of the displayed columns.
191
+
192
+ ```ruby
193
+ class UserTabulatrData < Tabulatr::Data
194
+ filter :age_range do |relation, value|
195
+ if value == 'upto_18'
196
+ relation.where("birthday > ?", Date.today-18.years)
197
+ elsif value == 'over_18'
198
+ relation.where("birthday <= ?", Date.today-18.years)
199
+ end
200
+ end
201
+ end
202
+ ```
203
+
204
+ This code will look for a partial to render in `tabulatr/filter/_age_range.*`.
205
+ You can override this path by specifying the `partial` argument of the `filter` method.
206
+ It will call it's block with the ActiveRecord::Relation and the submitted value after
207
+ the user submits the filter form.
208
+
209
+ ```erb
210
+ # tabulatr/filter/_age_range.html.erb
211
+
212
+ <div class='form-group'>
213
+ <label class='control-label' for="<%= input_id %>">Age range</label>
214
+ <select id="<%= input_id %>" name="<%= input_name %>">
215
+ <option value=''>None</option>
216
+ <option value='upto_18'>0 - 17</option>
217
+ <option value='over_18'>18+</option>
218
+ </select>
219
+ </div>
220
+ ```
221
+
222
+ As you can see there are two locales defined which should be used for your custom form
223
+ field: `input_name` and `input_id`
224
+
187
225
  ### Row formatting
188
226
 
189
227
  To provide row specific HTML-Attributes call `row`:
@@ -19,8 +19,8 @@ $(function(){
19
19
  elem = $('[name="'+ objKeys[i] +'"]');
20
20
  if(elem.length > 0){
21
21
  var val = currentStorage[objKeys[i]];
22
- elem.val(val);
23
- formParent = elem.parents('.form-group[data-filter-column-name]');
22
+ elem.val(val).trigger('change');
23
+ formParent = elem.parents('.tabulatr-filter-row');
24
24
  if(formParent.length > 0 && val && val.length > 0){
25
25
  $('.tabulatr-outer-wrapper[data-table-id="'+this.id+'"]').addClass('filtered')
26
26
  }
@@ -34,7 +34,7 @@ $(function(){
34
34
  localStorage.removeItem(this.id);
35
35
  $('table#'+ this.id).find('th.sorted').removeClass('sorted').removeAttr('data-sorted');
36
36
  $('form[data-table='+ this.id +'] input.search').val('');
37
- $('[data-table-id="'+ this.id +'"] [data-filter-column-name]').find('input[type=text], input[type=hidden], select').val('');
37
+ $('.tabulatr_filter_form[data-table="'+ this.id +'"]').find('input[type=text], input[type=hidden], select').val('');
38
38
  $('.tabulatr_filter_form[data-table='+ this.id +'] input[name="'+ tableName +'_sort"]').val('');
39
39
  this.updateTable({page: 1}, true);
40
40
  };
@@ -103,3 +103,8 @@
103
103
  = label_tag "check_box_#{key}", key
104
104
  - else
105
105
  input.tabulatr_filter.form-control type="text" data-tabulatr-attribute="#{name}" name="#{iname}[like]"
106
+ - filter.each do |f|
107
+ .row.tabulatr-filter-row
108
+ .col-xs-12
109
+ = render f.to_partial_path, {input_name: "#{formatted_name}_filter[#{f.name}]",
110
+ input_id: "#{formatted_name}_#{f.name}"}
@@ -21,7 +21,7 @@
21
21
 
22
22
  - opts = { columns: columns, table_options: table_options, \
23
23
  klass: klass, classname: classname, table_id: table_id,
24
- formatted_name: formatted_name }
24
+ formatted_name: formatted_name, filter: filter }
25
25
 
26
26
  .row.tabulatr-outer-wrapper data-table-id=table_id
27
27
  .tabulatr-filter-col data-table-id=table_id
@@ -95,6 +95,10 @@ class Tabulatr::Data
95
95
  self.class.instance_variable_get("@table_columns")
96
96
  end
97
97
 
98
+ def filters
99
+ self.class.instance_variable_get('@filters')
100
+ end
101
+
98
102
  def search?
99
103
  self.class.instance_variable_get('@search')
100
104
  end
@@ -157,6 +157,11 @@ module Tabulatr::Data::DSL
157
157
  @row = block
158
158
  end
159
159
 
160
+ def filter(name, partial: nil, &block)
161
+ @filters ||= []
162
+ @filters << Tabulatr::Renderer::Filter.new(name, partial: partial, &block)
163
+ end
164
+
160
165
  end
161
166
 
162
167
  Tabulatr::Data.send :extend, Tabulatr::Data::DSL
@@ -45,12 +45,13 @@ module Tabulatr::Data::Filtering
45
45
  return unless filter_params
46
46
  assoc_filters = filter_params.delete :__association
47
47
  apply_association_filters(assoc_filters) if assoc_filters.present?
48
- filter_params.each do |filter|
49
- name, value = filter
48
+ filter_params.each do |param|
49
+ name, value = param
50
50
  next unless value.present?
51
51
 
52
52
  table_name, method_name = name.split(':').map(&:to_sym)
53
53
  column = table_columns.find{|c| c.table_name == table_name && c.name == method_name}
54
+ column = filters.find{|f| f.name.to_sym == name.to_sym} if column.nil?
54
55
  apply_condition(column, value)
55
56
  end
56
57
  end
@@ -78,6 +79,7 @@ module Tabulatr::Data::Filtering
78
79
  when :like then apply_like_condition(n, v[:like])
79
80
  when :date then apply_date_condition(n, v[:date])
80
81
  when :range then apply_range_condition(n, v)
82
+ when :custom then apply_custom_filter(n, v)
81
83
  else raise "Wrong filter type for #{n.name}: #{n.filter}"
82
84
  end
83
85
  end
@@ -134,6 +136,11 @@ module Tabulatr::Data::Filtering
134
136
  @relation = @relation.where(column.table_name => { column.name => value })
135
137
  end
136
138
 
139
+ def apply_custom_filter(filter, value)
140
+ filter_result = filter.block.(@relation, value)
141
+ handle_search_result(filter_result)
142
+ end
143
+
137
144
  private
138
145
 
139
146
  def execute_provided_search_block!(query)
@@ -28,7 +28,7 @@ module Tabulatr::Data::Pagination
28
28
  end
29
29
 
30
30
  def compute_pagination(page, pagesize)
31
- count = @relation.count
31
+ count = @relation.to_a.size
32
32
  page ||= 1
33
33
  pagesize, page = pagesize.to_i, page.to_i
34
34
 
@@ -30,6 +30,7 @@ class ActionController::Base
30
30
  klass = relation.respond_to?(:klass) ? relation.klass : relation
31
31
  respond_to do |format|
32
32
  format.json {
33
+ locals[:current_user] ||= current_user if respond_to?(:current_user)
33
34
  records = klass.tabulatr(relation, tabulatr_data_class).data_for_table(params, locals: locals, controller: self, &block)
34
35
  render json: records.to_tabulatr_json(serializer)
35
36
  records
@@ -23,13 +23,12 @@
23
23
 
24
24
  class ActionView::Base
25
25
  # render the table in a view
26
- def table_for(klass, columns: [], tabulatr_data_class: nil, **opts, &block)
26
+ def table_for(klass, columns: [], filter: [], tabulatr_data_class: nil, **opts, &block)
27
27
  @_tabulatr_table_index += 1
28
- Tabulatr::Renderer.build_table(klass, self, opts, columns, tabulatr_data_class, &block)
28
+ Tabulatr::Renderer.build_table(klass, self, opts, columns, filter, tabulatr_data_class, &block)
29
29
  end
30
30
 
31
31
  def static_table_for(records, opts={}, &block)
32
32
  Tabulatr::Renderer.build_static_table(records, self, opts, &block)
33
33
  end
34
34
  end
35
-
@@ -23,12 +23,13 @@
23
23
 
24
24
  class Tabulatr::Renderer
25
25
  class ColumnsFromBlock
26
- attr_accessor :columns, :klass, :table_data
26
+ attr_accessor :columns, :klass, :table_data, :filters
27
27
 
28
28
  def initialize(klass, table_data_object)
29
29
  @klass = klass
30
30
  @table_data = table_data_object
31
31
  @columns ||= []
32
+ @filters ||= []
32
33
  end
33
34
 
34
35
  def column(name, opts={}, &block)
@@ -65,11 +66,19 @@ class Tabulatr::Renderer
65
66
  @columns << Buttons.from(opts.merge(klass: klass, filter: false, sortable: false, output: output), &block)
66
67
  end
67
68
 
69
+ def filter(name, partial: nil, &block)
70
+ if table_data
71
+ found_filter = fetch_filter_from_table_data(name)
72
+ @filters << found_filter if found_filter.present?
73
+ else
74
+ @filters << Tabulatr::Renderer::Filter.new(name, partial: partial, &block)
75
+ end
76
+ end
77
+
68
78
  def self.process(klass, table_data_object = nil, &block)
69
79
  i = self.new(klass, table_data_object)
70
80
  yield(i)
71
- c = i.columns
72
- c
81
+ i
73
82
  end
74
83
 
75
84
  private
@@ -78,5 +87,9 @@ class Tabulatr::Renderer
78
87
  column = table_data.table_columns.find{|tc| tc.table_name == table_name && tc.name == name}
79
88
  column.update_options(opts, &block)
80
89
  end
90
+
91
+ def fetch_filter_from_table_data name
92
+ table_data.filters.find{|f| f.name.to_sym == name.to_sym}
93
+ end
81
94
  end
82
95
  end
@@ -0,0 +1,22 @@
1
+ class Tabulatr::Renderer::Filter
2
+
3
+ attr_accessor :name, :partial, :block
4
+
5
+ def initialize(name, partial: nil, &block)
6
+ @name = name
7
+ @block = block
8
+ @partial = partial
9
+ end
10
+
11
+ def filter
12
+ :custom
13
+ end
14
+
15
+ def to_partial_path
16
+ if partial.present?
17
+ partial
18
+ else
19
+ "tabulatr/filter/#{name.to_s.downcase.underscore}"
20
+ end
21
+ end
22
+ end
@@ -57,16 +57,17 @@ class Tabulatr::Renderer
57
57
  @classname = @klass.name.underscore
58
58
  end
59
59
 
60
- def build_table(columns, tabulatr_data_class, &block)
60
+ def build_table(columns, filters, tabulatr_data_class, &block)
61
61
  if tabulatr_data_class.present?
62
62
  tdc = tabulatr_data_class.constantize.new(@klass)
63
63
  else
64
64
  tdc = "#{@klass.name}TabulatrData".constantize.new(@klass)
65
65
  end
66
66
  if block_given?
67
- @columns = ColumnsFromBlock.process @klass, tdc, &block
68
- elsif columns.any?
67
+ @columns = ColumnsFromBlock.process(@klass, tdc, &block).columns
68
+ elsif columns.any? || filters.any?
69
69
  @columns = get_requested_columns(tdc.table_columns, columns)
70
+ @filters = get_requested_filters(tdc.filters, filters)
70
71
  else
71
72
  @columns = tdc.table_columns
72
73
  end
@@ -77,12 +78,13 @@ class Tabulatr::Renderer
77
78
  classname: @classname,
78
79
  tabulatr_data: tdc,
79
80
  table_id: generate_id,
80
- formatted_name: Tabulatr::Utility.formatted_name(@klass.name)
81
+ formatted_name: Tabulatr::Utility.formatted_name(@klass.name),
82
+ filter: tdc.filters || []
81
83
  })
82
84
  end
83
85
 
84
86
  def build_static_table(records, &block)
85
- @columns = ColumnsFromBlock.process @klass, &block
87
+ @columns = ColumnsFromBlock.process(@klass, &block).columns
86
88
 
87
89
  @view.render(partial: '/tabulatr/tabulatr_static_table', locals: {
88
90
  columns: @columns,
@@ -103,8 +105,8 @@ class Tabulatr::Renderer
103
105
  new(klass, view, toptions).build_static_table(records, &block)
104
106
  end
105
107
 
106
- def self.build_table(klass, view, toptions={}, columns, tabulatr_data_class, &block)
107
- new(klass, view, toptions).build_table(columns, tabulatr_data_class, &block)
108
+ def self.build_table(klass, view, toptions={}, columns, filters, tabulatr_data_class, &block)
109
+ new(klass, view, toptions).build_table(columns, filters, tabulatr_data_class, &block)
108
110
  end
109
111
 
110
112
  private
@@ -121,6 +123,13 @@ class Tabulatr::Renderer
121
123
  end.flatten
122
124
  end
123
125
 
126
+ def get_requested_filters(available_filters, requested_filters)
127
+ requested_filters.collect do |f|
128
+ result = available_filters.find{|filter| filter.name.to_sym == f.to_sym }
129
+ result or raise "Can't find filter '#{f}'"
130
+ end.flatten
131
+ end
132
+
124
133
  end
125
134
 
126
135
  require_relative './column'
@@ -129,3 +138,4 @@ require_relative './action'
129
138
  require_relative './buttons'
130
139
  require_relative './checkbox'
131
140
  require_relative './columns_from_block'
141
+ require_relative './filter'
@@ -22,5 +22,5 @@
22
22
  #++
23
23
 
24
24
  module Tabulatr
25
- VERSION = "0.9.19"
25
+ VERSION = "0.9.20"
26
26
  end
@@ -0,0 +1,34 @@
1
+ require 'rails_helper'
2
+
3
+ # RSpec.configure do |c|
4
+ # c.infer_base_class_for_anonymous_controllers = false
5
+ # end
6
+
7
+ describe ApplicationController, type: :controller do
8
+ controller do
9
+ def index
10
+ tabulatr_for Product
11
+ end
12
+
13
+ def current_user
14
+ "Han Solo"
15
+ end
16
+ end
17
+
18
+ describe "passing locales to Tabulatr::Data" do
19
+ it "implicitly creates a current_user local if not already present" do
20
+ request.accept = "application/json"
21
+ Product.create!(:title => 'bar', :active => true, :price => 10.0)
22
+ fake_response = double({foo: 'bar'})
23
+
24
+ expect_any_instance_of(Tabulatr::Data).to receive(:data_for_table).with(
25
+ {"pagesize"=>"20", "arguments"=>"products:title", "controller"=>"anonymous", "action"=>"index"},
26
+ {:locals=>{current_user: "Han Solo"}, controller: controller}
27
+ ).and_return(fake_response)
28
+ expect(fake_response).to receive(:to_tabulatr_json).and_return({})
29
+
30
+ get :index, pagesize: 20, arguments: 'products:title'
31
+ expect(response.code).to eq '200'
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ class VendorTabulatrData < Tabulatr::Data
2
+
3
+ column :name
4
+ column :url
5
+ column :active
6
+
7
+ filter :product_price_range do |relation, value|
8
+ relation = relation.joins(:products)
9
+ if value == 'low'
10
+ relation.group("vendors.id").having('AVG(products.price) <= 100')
11
+ elsif value == 'high'
12
+ relation.group("vendors.id").having('AVG(products.price) > 100')
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ .form-group.control-group
2
+ label.control-label for=input_id Price range (avg.)
3
+
4
+ select.form-control.no-chosen id=input_id name=input_name
5
+ option= I18n.t("tabulatr.date_filter.none")
6
+ option value="low"
7
+ | <= 100 Euro
8
+ option value="high"
9
+ | > 100 Euro
@@ -0,0 +1 @@
1
+ = table_for Vendor, paginate: true
@@ -215,6 +215,24 @@ feature "Tabulatr" do
215
215
  expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'bar')
216
216
  expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'foo')
217
217
  end
218
+
219
+ scenario 'custom filters', js: true do
220
+ Product.create!([{title: 'foo', price: 7.5, vendor: @vendor1}, {title: 'bar', price: 90, vendor: @vendor1}])
221
+ Product.create!([{title: 'baz', price: 125, vendor: @vendor2}, {title: 'fubar', price: 133.3, vendor: @vendor2}, {title: 'fiz', price: 97, vendor: @vendor2}])
222
+ visit vendors_path
223
+ expect(page).to have_css(".tabulatr_table tbody tr", count: 2)
224
+ click_link 'Filter'
225
+ within(".tabulatr_filter_form") do
226
+ select("> 100 Euro", from: "vendor_filter[product_price_range]")
227
+ end
228
+ expect(page).to have_css(".tabulatr_table tbody tr", count: 1)
229
+ expect(page).to have_css('.tabulatr_table tbody td', text: @vendor2.name)
230
+ within(".tabulatr_filter_form") do
231
+ select("<= 100 Euro", from: "vendor_filter[product_price_range]")
232
+ end
233
+ expect(page).to have_css(".tabulatr_table tbody tr", count: 1)
234
+ expect(page).to have_css('.tabulatr_table tbody td', text: @vendor1.name)
235
+ end
218
236
  end
219
237
 
220
238
  feature "Sorting" do
@@ -7,11 +7,12 @@ describe Tabulatr::Data::DSL do
7
7
 
8
8
  before(:each) do
9
9
  DummyDSLClass.instance_variable_set('@table_columns', [])
10
+ DummyDSLClass.instance_variable_set('@filters', [])
11
+ allow(DummyDSLClass).to receive(:main_class).and_return(Product)
10
12
  end
11
13
 
12
14
  describe '#column' do
13
15
  it 'escapes table and column names' do
14
- allow(DummyDSLClass).to receive(:main_class).and_return(Product)
15
16
  DummyDSLClass.column(:active)
16
17
  table_column = DummyDSLClass.instance_variable_get('@table_columns').first
17
18
  expect(table_column.filter_sql).to match(/\"products\".\"active\"/)
@@ -21,11 +22,28 @@ describe Tabulatr::Data::DSL do
21
22
 
22
23
  describe '#association' do
23
24
  it 'escapes table and column names' do
24
- allow(DummyDSLClass).to receive(:main_class).and_return(Product)
25
25
  DummyDSLClass.association(:vendor, :name)
26
26
  table_column = DummyDSLClass.instance_variable_get('@table_columns').first
27
27
  expect(table_column.filter_sql).to match(/\"vendors\".\"name\"/)
28
28
  expect(table_column.sort_sql).to match(/\"vendors\".\"name\"/)
29
29
  end
30
30
  end
31
- end
31
+
32
+ describe '#filter' do
33
+ it 'adds filters' do
34
+ DummyDSLClass.filter(:price_range)
35
+ expect(DummyDSLClass.instance_variable_get('@filters').map(&:name)).to match_array([:price_range])
36
+ end
37
+
38
+ it 'can hold multiple filters' do
39
+ DummyDSLClass.filter(:price_range)
40
+ DummyDSLClass.filter(:category_select)
41
+ expect(DummyDSLClass.instance_variable_get('@filters').map(&:name)).to match_array([:price_range, :category_select])
42
+ end
43
+
44
+ it 'accepts a partial attribute' do
45
+ DummyDSLClass.filter(:simple_filter, partial: 'my_custom_filter')
46
+ expect(DummyDSLClass.instance_variable_get('@filters').first.partial).to eq 'my_custom_filter'
47
+ end
48
+ end
49
+ end
@@ -3,23 +3,28 @@ require 'rails_helper'
3
3
  describe Tabulatr::Data::Filtering do
4
4
  class DummyFilteringClass
5
5
  include Tabulatr::Data::Filtering
6
- end
7
6
 
8
- before(:each) do
9
- @dummy = DummyFilteringClass.new
10
- @dummy.instance_variable_set('@relation', Product.all)
11
- @yesterday = Product.create!(publish_at: DateTime.new(2013, 12, 31, 0, 0))
12
- @today = Product.create!(publish_at: DateTime.new(2014, 1, 1, 15, 0))
13
- @week_one = Product.create!(publish_at: DateTime.new(2013, 12, 30, 0, 0))
14
- @week_two = Product.create!(publish_at: DateTime.new(2014, 1, 5, 8, 0))
15
- @last_seven_days = Product.create!(publish_at: DateTime.new(2013, 12, 26, 0, 0))
16
- @last_thirty_days = Product.create!(publish_at: DateTime.new(2013, 12, 3, 0, 0))
17
- @outside_last_thirty_days = Product.create!(publish_at: DateTime.new(2013, 12, 2, 23, 59))
18
- @this_month = Product.create!(publish_at: DateTime.new(2014, 1, 15, 0, 0))
19
- @next_year = Product.create!(publish_at: DateTime.new(2015, 1, 1, 12, 0))
20
- allow(Date).to receive(:today).and_return(Date.new(2014,1,1))
7
+ def table_columns; []; end
8
+ def filters; []; end
21
9
  end
10
+
22
11
  describe '.apply_date_condition' do
12
+ before(:each) do
13
+ @dummy = DummyFilteringClass.new
14
+ @dummy.instance_variable_set('@relation', Product.all)
15
+ @yesterday = Product.create!(publish_at: DateTime.new(2013, 12, 31, 0, 0))
16
+ @today = Product.create!(publish_at: DateTime.new(2014, 1, 1, 15, 0))
17
+ @week_one = Product.create!(publish_at: DateTime.new(2013, 12, 30, 0, 0))
18
+ @week_two = Product.create!(publish_at: DateTime.new(2014, 1, 5, 8, 0))
19
+ @last_seven_days = Product.create!(publish_at: DateTime.new(2013, 12, 26, 0, 0))
20
+ @last_thirty_days = Product.create!(publish_at: DateTime.new(2013, 12, 3, 0, 0))
21
+ @outside_last_thirty_days = Product.create!(publish_at: DateTime.new(2013, 12, 2, 23, 59))
22
+ @this_month = Product.create!(publish_at: DateTime.new(2014, 1, 15, 0, 0))
23
+ @next_year = Product.create!(publish_at: DateTime.new(2015, 1, 1, 12, 0))
24
+ allow(Date).to receive(:today).and_return(Date.new(2014,1,1))
25
+ end
26
+
27
+
23
28
  it "filters for 'today'" do
24
29
  fake_obj = double(filter_sql: 'publish_at')
25
30
  @dummy.apply_date_condition(fake_obj, {simple: 'today'})
@@ -78,6 +83,12 @@ describe Tabulatr::Data::Filtering do
78
83
  end
79
84
 
80
85
  describe '.apply_search' do
86
+
87
+ before(:each) do
88
+ @dummy = DummyFilteringClass.new
89
+ @dummy.instance_variable_set('@relation', Product.all)
90
+ end
91
+
81
92
  it 'allows to alter the ActiveRecord::Relation' do
82
93
  @dummy.instance_variable_set('@search',
83
94
  ->(query, relation){ relation.joins(:vendor).where(%{vendors.name LIKE '%#{query}%'})})
@@ -110,4 +121,29 @@ describe Tabulatr::Data::Filtering do
110
121
  expect{@dummy.apply_search('test')}.to raise_error
111
122
  end
112
123
  end
124
+
125
+ describe '.apply_filters' do
126
+ before(:each) do
127
+ @dummy = DummyFilteringClass.new
128
+ @dummy.instance_variable_set('@relation', Product.all)
129
+ end
130
+
131
+ it 'applies given filters to the relation' do
132
+ bl = ->(relation, value){ relation.where(price: value) }
133
+ allow(@dummy).to receive(:filters).and_return([Tabulatr::Renderer::Filter.new(:custom_filter, &bl)])
134
+ matched_product = Product.create(price: 10)
135
+ unmatched_product = Product.create(price: 11)
136
+ expect{@dummy.apply_filters({'custom_filter' => '10'})}.to_not raise_error
137
+ result = @dummy.instance_variable_get('@relation')
138
+ expect(result).to match_array([matched_product])
139
+ end
140
+
141
+ it 'only searches for a filter if there is no column with that name' do
142
+ fake_column = double(table_name: :custom, name: nil)
143
+ allow(@dummy).to receive(:table_columns).and_return([fake_column])
144
+ allow(@dummy).to receive(:filters).and_return([Tabulatr::Renderer::Filter.new(:custom)])
145
+ expect(@dummy).to receive(:apply_condition).with(fake_column, '10')
146
+ @dummy.apply_filters({'custom' => '10'})
147
+ end
148
+ end
113
149
  end
@@ -10,7 +10,7 @@ describe Tabulatr::Data::Pagination do
10
10
  end
11
11
  describe '.compute_pagination' do
12
12
  it "computes an offset" do
13
- count = double(count: 20)
13
+ count = (1..20).to_a
14
14
  @dummy.instance_variable_set('@relation', count)
15
15
  pagination = @dummy.compute_pagination(1, 10)
16
16
  expect(pagination[:offset]).to be 0
@@ -0,0 +1,21 @@
1
+ require 'rails_helper'
2
+
3
+ describe Tabulatr::Renderer::ColumnsFromBlock do
4
+
5
+ class TabulatrFakeData < Tabulatr::Data
6
+ filter :foo_and_bar
7
+ filter :not_requested_filter
8
+ end
9
+
10
+ describe '#filter' do
11
+ it 'finds filters if tabulatr_data is given' do
12
+ allow_any_instance_of(TabulatrFakeData).to receive(:table_columns).and_return([])
13
+ td = TabulatrFakeData.new(Product)
14
+ cfb = Tabulatr::Renderer::ColumnsFromBlock.process(Product, td) do |c|
15
+ c.filter :foo_and_bar
16
+ c.filter :not_available_filter
17
+ end
18
+ expect(cfb.filters.map(&:name)).to match_array([:foo_and_bar])
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails_helper'
2
+
3
+ describe Tabulatr::Renderer::Filter do
4
+ describe '#to_partial_path' do
5
+ it 'guesses the partial_path by name if no partial is given' do
6
+ filter = Tabulatr::Renderer::Filter.new('dynamic_select')
7
+ expect(filter.to_partial_path).to eq 'tabulatr/filter/dynamic_select'
8
+ end
9
+
10
+ it 'uses the given partial name if given' do
11
+ filter = Tabulatr::Renderer::Filter.new('some_filter', partial: 'my_filters/simple_filter')
12
+ expect(filter.to_partial_path).to eq 'my_filters/simple_filter'
13
+ end
14
+ end
15
+ end
@@ -2,6 +2,10 @@ require 'rails_helper'
2
2
 
3
3
  describe Tabulatr::Renderer do
4
4
 
5
+ class FakeRendererSpecTabulatrData < Tabulatr::Data
6
+ filter :simple_filter
7
+ end
8
+
5
9
  def double_view
6
10
  view = double(controller: double(controller_name: 'products', action_name: 'index'), render: '')
7
11
  view.instance_variable_set('@_tabulatr_table_index', 0)
@@ -28,10 +32,18 @@ describe Tabulatr::Renderer do
28
32
  describe '#build_table' do
29
33
  it 'gets columns by their names' do
30
34
  renderer = Tabulatr::Renderer.new(Product, double_view)
31
- renderer.build_table(['_buttons'], 'ProductTabulatrData')
35
+ renderer.build_table(['_buttons'], [], 'ProductTabulatrData')
32
36
  columns = renderer.instance_variable_get('@columns')
33
37
  expect(columns.count).to be(1)
34
38
  expect(columns.first).to be_instance_of(Tabulatr::Renderer::Buttons)
35
39
  end
40
+
41
+ it 'gets filters by their names' do
42
+ allow_any_instance_of(Tabulatr::Data).to receive(:table_columns).and_return([])
43
+ renderer = Tabulatr::Renderer.new(Product, double_view)
44
+ renderer.build_table([], [:simple_filter], 'FakeRendererSpecTabulatrData')
45
+ filters = renderer.instance_variable_get('@filters')
46
+ expect(filters.map(&:name)).to match_array([:simple_filter])
47
+ end
36
48
  end
37
49
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tabulatr2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.19
4
+ version: 0.9.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Horn
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-04-29 00:00:00.000000000 Z
13
+ date: 2015-05-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -165,12 +165,14 @@ files:
165
165
  - lib/tabulatr/renderer/checkbox.rb
166
166
  - lib/tabulatr/renderer/column.rb
167
167
  - lib/tabulatr/renderer/columns_from_block.rb
168
+ - lib/tabulatr/renderer/filter.rb
168
169
  - lib/tabulatr/renderer/renderer.rb
169
170
  - lib/tabulatr/utility/request_data_not_included_error.rb
170
171
  - lib/tabulatr/utility/unexpected_search_result_error.rb
171
172
  - lib/tabulatr/utility/utility.rb
172
173
  - lib/tabulatr/version.rb
173
174
  - lib/tabulatr2.rb
175
+ - spec/controller/application_controller_spec.rb
174
176
  - spec/dummy/.gitignore
175
177
  - spec/dummy/README.rdoc
176
178
  - spec/dummy/Rakefile
@@ -190,6 +192,7 @@ files:
190
192
  - spec/dummy/app/models/tag.rb
191
193
  - spec/dummy/app/models/vendor.rb
192
194
  - spec/dummy/app/tabulatr_data/product_tabulatr_data.rb
195
+ - spec/dummy/app/tabulatr_data/vendor_tabulatr_data.rb
193
196
  - spec/dummy/app/views/layouts/application.html.erb
194
197
  - spec/dummy/app/views/products/count_tags.html.erb
195
198
  - spec/dummy/app/views/products/implicit_columns.html.erb
@@ -199,6 +202,8 @@ files:
199
202
  - spec/dummy/app/views/products/stupid_array.html.erb
200
203
  - spec/dummy/app/views/products/with_batch_actions.html.erb
201
204
  - spec/dummy/app/views/products/with_styling.html.erb
205
+ - spec/dummy/app/views/tabulatr/filter/_product_price_range.html.slim
206
+ - spec/dummy/app/views/vendors/index.html.slim
202
207
  - spec/dummy/bin/bundle
203
208
  - spec/dummy/bin/rails
204
209
  - spec/dummy/bin/rake
@@ -241,6 +246,8 @@ files:
241
246
  - spec/lib/tabulatr/data/sorting_spec.rb
242
247
  - spec/lib/tabulatr/json_builder_spec.rb
243
248
  - spec/lib/tabulatr/renderer/checkbox_spec.rb
249
+ - spec/lib/tabulatr/renderer/columns_from_block_spec.rb
250
+ - spec/lib/tabulatr/renderer/filter_spec.rb
244
251
  - spec/lib/tabulatr/renderer/renderer_spec.rb
245
252
  - spec/rails_helper.rb
246
253
  - spec/spec_helper.rb
@@ -273,6 +280,7 @@ specification_version: 4
273
280
  summary: A tight DSL to build tables of ActiveRecord models with sorting, pagination,
274
281
  finding/filtering, selecting and batch actions.
275
282
  test_files:
283
+ - spec/controller/application_controller_spec.rb
276
284
  - spec/dummy/.gitignore
277
285
  - spec/dummy/README.rdoc
278
286
  - spec/dummy/Rakefile
@@ -292,6 +300,7 @@ test_files:
292
300
  - spec/dummy/app/models/tag.rb
293
301
  - spec/dummy/app/models/vendor.rb
294
302
  - spec/dummy/app/tabulatr_data/product_tabulatr_data.rb
303
+ - spec/dummy/app/tabulatr_data/vendor_tabulatr_data.rb
295
304
  - spec/dummy/app/views/layouts/application.html.erb
296
305
  - spec/dummy/app/views/products/count_tags.html.erb
297
306
  - spec/dummy/app/views/products/implicit_columns.html.erb
@@ -301,6 +310,8 @@ test_files:
301
310
  - spec/dummy/app/views/products/stupid_array.html.erb
302
311
  - spec/dummy/app/views/products/with_batch_actions.html.erb
303
312
  - spec/dummy/app/views/products/with_styling.html.erb
313
+ - spec/dummy/app/views/tabulatr/filter/_product_price_range.html.slim
314
+ - spec/dummy/app/views/vendors/index.html.slim
304
315
  - spec/dummy/bin/bundle
305
316
  - spec/dummy/bin/rails
306
317
  - spec/dummy/bin/rake
@@ -343,6 +354,8 @@ test_files:
343
354
  - spec/lib/tabulatr/data/sorting_spec.rb
344
355
  - spec/lib/tabulatr/json_builder_spec.rb
345
356
  - spec/lib/tabulatr/renderer/checkbox_spec.rb
357
+ - spec/lib/tabulatr/renderer/columns_from_block_spec.rb
358
+ - spec/lib/tabulatr/renderer/filter_spec.rb
346
359
  - spec/lib/tabulatr/renderer/renderer_spec.rb
347
360
  - spec/rails_helper.rb
348
361
  - spec/spec_helper.rb