tabulatr2 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +4 -0
  5. data/Changelog.textile +124 -0
  6. data/Gemfile +21 -0
  7. data/LICENSE +23 -0
  8. data/README.md +242 -0
  9. data/Rakefile +11 -0
  10. data/app/assets/images/tabulatr/buttons_lite_background.png +0 -0
  11. data/app/assets/images/tabulatr/pager_arrow_left.gif +0 -0
  12. data/app/assets/images/tabulatr/pager_arrow_left_off.gif +0 -0
  13. data/app/assets/images/tabulatr/pager_arrow_right.gif +0 -0
  14. data/app/assets/images/tabulatr/pager_arrow_right_off.gif +0 -0
  15. data/app/assets/images/tabulatr/sort_arrow_down.gif +0 -0
  16. data/app/assets/images/tabulatr/sort_arrow_down_off.gif +0 -0
  17. data/app/assets/images/tabulatr/sort_arrow_up.gif +0 -0
  18. data/app/assets/images/tabulatr/sort_arrow_up_off.gif +0 -0
  19. data/app/assets/javascripts/tabulatr/application.js +452 -0
  20. data/app/assets/javascripts/tabulatr/jquery.inview.min.js +3 -0
  21. data/app/assets/javascripts/tabulatr.js +1 -0
  22. data/app/assets/stylesheets/tabulatr/application.css +40 -0
  23. data/app/assets/stylesheets/tabulatr.css +4 -0
  24. data/init.rb +1 -0
  25. data/lib/generators/tabulatr/install_generator.rb +44 -0
  26. data/lib/generators/tabulatr/templates/tabulatr.rb +5 -0
  27. data/lib/generators/tabulatr/templates/tabulatr.yml +14 -0
  28. data/lib/initializers/action_controller.rb +13 -0
  29. data/lib/initializers/action_view.rb +31 -0
  30. data/lib/initializers/active_record.rb +48 -0
  31. data/lib/initializers/mark_as_localizable.rb +43 -0
  32. data/lib/tabulatr/engine.rb +3 -0
  33. data/lib/tabulatr/tabulatr/adapter/active_record.rb +84 -0
  34. data/lib/tabulatr/tabulatr/adapter.rb +55 -0
  35. data/lib/tabulatr/tabulatr/batch_actions.rb +51 -0
  36. data/lib/tabulatr/tabulatr/data_cell.rb +132 -0
  37. data/lib/tabulatr/tabulatr/dummy_record.rb +40 -0
  38. data/lib/tabulatr/tabulatr/empty_cell.rb +44 -0
  39. data/lib/tabulatr/tabulatr/filter_cell.rb +145 -0
  40. data/lib/tabulatr/tabulatr/filter_icon.rb +6 -0
  41. data/lib/tabulatr/tabulatr/finder/find_for_table.rb +187 -0
  42. data/lib/tabulatr/tabulatr/finder.rb +64 -0
  43. data/lib/tabulatr/tabulatr/formattr.rb +55 -0
  44. data/lib/tabulatr/tabulatr/header_cell.rb +146 -0
  45. data/lib/tabulatr/tabulatr/json_builder.rb +57 -0
  46. data/lib/tabulatr/tabulatr/paginator.rb +76 -0
  47. data/lib/tabulatr/tabulatr/row_builder.rb +128 -0
  48. data/lib/tabulatr/tabulatr/security.rb +21 -0
  49. data/lib/tabulatr/tabulatr/settings.rb +158 -0
  50. data/lib/tabulatr/tabulatr.rb +343 -0
  51. data/lib/tabulatr/version.rb +3 -0
  52. data/lib/tabulatr.rb +34 -0
  53. data/spec/dummy/.gitignore +18 -0
  54. data/spec/dummy/README.rdoc +28 -0
  55. data/spec/dummy/Rakefile +6 -0
  56. data/spec/dummy/app/assets/images/.keep +0 -0
  57. data/spec/dummy/app/assets/javascripts/application.js +16 -0
  58. data/spec/dummy/app/assets/stylesheets/application.css.scss +15 -0
  59. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  60. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  61. data/spec/dummy/app/controllers/products_controller.rb +24 -0
  62. data/spec/dummy/app/controllers/tags_controller.rb +5 -0
  63. data/spec/dummy/app/controllers/vendors_controller.rb +5 -0
  64. data/spec/dummy/app/helpers/application_helper.rb +9 -0
  65. data/spec/dummy/app/mailers/.keep +0 -0
  66. data/spec/dummy/app/models/.keep +0 -0
  67. data/spec/dummy/app/models/concerns/.keep +0 -0
  68. data/spec/dummy/app/models/product.rb +5 -0
  69. data/spec/dummy/app/models/tag.rb +3 -0
  70. data/spec/dummy/app/models/vendor.rb +2 -0
  71. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  72. data/spec/dummy/app/views/products/count_tags.html.erb +9 -0
  73. data/spec/dummy/app/views/products/one_item_per_page.html.erb +9 -0
  74. data/spec/dummy/app/views/products/simple_index.html.erb +9 -0
  75. data/spec/dummy/app/views/products/stupid_array.html.erb +20 -0
  76. data/spec/dummy/bin/bundle +3 -0
  77. data/spec/dummy/bin/rails +4 -0
  78. data/spec/dummy/bin/rake +4 -0
  79. data/spec/dummy/config/application.rb +23 -0
  80. data/spec/dummy/config/boot.rb +5 -0
  81. data/spec/dummy/config/database.yml +25 -0
  82. data/spec/dummy/config/environment.rb +5 -0
  83. data/spec/dummy/config/environments/development.rb +29 -0
  84. data/spec/dummy/config/environments/production.rb +80 -0
  85. data/spec/dummy/config/environments/test.rb +36 -0
  86. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  87. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  88. data/spec/dummy/config/initializers/inflections.rb +16 -0
  89. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  90. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  91. data/spec/dummy/config/initializers/session_store.rb +3 -0
  92. data/spec/dummy/config/initializers/tabulatr.rb +5 -0
  93. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  94. data/spec/dummy/config/locales/en.yml +23 -0
  95. data/spec/dummy/config/locales/tabulatr.yml +14 -0
  96. data/spec/dummy/config/routes.rb +13 -0
  97. data/spec/dummy/config.ru +4 -0
  98. data/spec/dummy/db/migrate/20130730132101_create_vendors.rb +12 -0
  99. data/spec/dummy/db/migrate/20130730132321_create_products.rb +12 -0
  100. data/spec/dummy/db/migrate/20130730132348_create_tags.rb +14 -0
  101. data/spec/dummy/db/schema.rb +47 -0
  102. data/spec/dummy/lib/assets/.keep +0 -0
  103. data/spec/dummy/log/.keep +0 -0
  104. data/spec/dummy/public/404.html +58 -0
  105. data/spec/dummy/public/422.html +58 -0
  106. data/spec/dummy/public/500.html +57 -0
  107. data/spec/dummy/public/favicon.ico +0 -0
  108. data/spec/features/tabulatrs_spec.rb +227 -0
  109. data/spec/lib/tabulatr/tabulatr/finder/find_for_table_spec.rb +187 -0
  110. data/spec/spec_helper.rb +45 -0
  111. data/tabulatr.gemspec +29 -0
  112. metadata +258 -0
@@ -0,0 +1,14 @@
1
+ class CreateTags < ActiveRecord::Migration
2
+ def change
3
+ create_table :tags do |t|
4
+ t.string :title
5
+
6
+ t.timestamps
7
+ end
8
+
9
+ create_table :products_tags, id: false do |t|
10
+ t.references :tag
11
+ t.references :product
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 20130730132348) do
15
+
16
+ create_table "products", force: true do |t|
17
+ t.integer "vendor_id"
18
+ t.string "title"
19
+ t.decimal "price"
20
+ t.boolean "active"
21
+ t.datetime "created_at"
22
+ t.datetime "updated_at"
23
+ end
24
+
25
+ add_index "products", ["vendor_id"], name: "index_products_on_vendor_id"
26
+
27
+ create_table "products_tags", id: false, force: true do |t|
28
+ t.integer "tag_id"
29
+ t.integer "product_id"
30
+ end
31
+
32
+ create_table "tags", force: true do |t|
33
+ t.string "title"
34
+ t.datetime "created_at"
35
+ t.datetime "updated_at"
36
+ end
37
+
38
+ create_table "vendors", force: true do |t|
39
+ t.string "name"
40
+ t.string "url"
41
+ t.boolean "active"
42
+ t.text "description"
43
+ t.datetime "created_at"
44
+ t.datetime "updated_at"
45
+ end
46
+
47
+ end
File without changes
File without changes
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/404.html -->
52
+ <div class="dialog">
53
+ <h1>The page you were looking for doesn't exist.</h1>
54
+ <p>You may have mistyped the address or the page may have moved.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/422.html -->
52
+ <div class="dialog">
53
+ <h1>The change you wanted was rejected.</h1>
54
+ <p>Maybe you tried to change something you didn't have access to.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/500.html -->
52
+ <div class="dialog">
53
+ <h1>We're sorry, but something went wrong.</h1>
54
+ </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
56
+ </body>
57
+ </html>
File without changes
@@ -0,0 +1,227 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Tabulatr" do
4
+
5
+ names = ["lorem", "ipsum", "dolor", "sit", "amet", "consectetur",
6
+ "adipisicing", "elit", "sed", "eiusmod", "tempor", "incididunt", "labore",
7
+ "dolore", "magna", "aliqua", "enim", "minim", "veniam,", "quis", "nostrud",
8
+ "exercitation", "ullamco", "laboris", "nisi", "aliquip", "commodo",
9
+ "consequat", "duis", "aute", "irure", "reprehenderit", "voluptate", "velit",
10
+ "esse", "cillum", "fugiat", "nulla", "pariatur", "excepteur", "sint",
11
+ "occaecat", "cupidatat", "non", "proident", "sunt", "culpa", "qui",
12
+ "officia", "deserunt", "mollit", "anim", "est", "laborum"]
13
+
14
+ before(:each) do
15
+ @vendor1 = Vendor.create!(:name => "ven d'or", :active => true)
16
+ @vendor2 = Vendor.create!(:name => 'producer', :active => true)
17
+ @tag1 = Tag.create!(:title => 'foo')
18
+ @tag2 = Tag.create!(:title => 'bar')
19
+ @tag3 = Tag.create!(:title => 'fubar')
20
+ end
21
+
22
+ describe "General data" do
23
+
24
+ it "contains buttons" do
25
+ visit simple_index_products_path
26
+ ['Filter'].each do |n|
27
+ page.should have_content(n)
28
+ end
29
+ end
30
+
31
+ it "contains column headers" do
32
+ visit simple_index_products_path
33
+ ['Title','Price','Active','Updated At'].each do |n|
34
+ find('.tabulatr_table thead').should have_content(n)
35
+ end
36
+ end
37
+
38
+ it "contains the actual data", js: true do
39
+ product = Product.create!(:title => names[0], :active => true, :price => 10.0)
40
+ product.vendor = @vendor1
41
+ product.save!
42
+ visit simple_index_products_path
43
+ page.should have_content("true")
44
+ page.should have_content("10.0")
45
+ product.vendor.name.should eq("ven d'or")
46
+ find('.tabulatr_table tbody').should have_content(names[0])
47
+ find('.tabulatr_table tbody').should have_content("ven d'or")
48
+ end
49
+
50
+ it "correctly contains the association data", js: true do
51
+ product = Product.create!(:title => names[0], :active => true, :price => 10.0)
52
+ [@tag1, @tag2, @tag3].each_with_index do |tag, i|
53
+ product.tags << tag
54
+ product.save
55
+ visit simple_index_products_path
56
+ page.should have_content tag.title
57
+ end
58
+ end
59
+
60
+ it "contains the actual data multiple", js: true do
61
+ 9.times do |i|
62
+ product = Product.create!(:title => names[i], :active => i.even?, :price => 11.0+i,
63
+ :vendor => i.even? ? @vendor1 : @vendor2)
64
+ visit simple_index_products_path
65
+ page.should have_content(names[i])
66
+ page.should have_content((11.0+i).to_s)
67
+ end
68
+ end
69
+
70
+ it "contains the further data on the further pages" do
71
+ names[10..-1].each_with_index do |n,i|
72
+ product = Product.create!(:title => n, :active => i.even?, :price => 20.0+i,
73
+ :vendor => i.even? ? @vendor1 : @vendor2)
74
+ visit simple_index_products_path
75
+ page.should_not have_content(n)
76
+ page.should_not have_content((30.0+i).to_s)
77
+ end
78
+ end
79
+ end
80
+
81
+ describe 'has_many' do
82
+ it 'displays the count when called with :count', js: true do
83
+ product = Product.create!(:title => names[0], :active => true, :price => 10.0)
84
+ [@tag1, @tag2, @tag3].each do |tag|
85
+ product.tags << tag
86
+ end
87
+ product.save
88
+ visit count_tags_products_path
89
+ page.should have_content 3
90
+ end
91
+ end
92
+
93
+ describe "Pagination" do
94
+
95
+
96
+ context 'pagination setting is true' do
97
+ it 'has pages', js: true do
98
+ 5.times do |i|
99
+ Product.create!(:title => "test #{i}")
100
+ end
101
+ visit one_item_per_page_with_pagination_products_path
102
+ page.all('.pagination li a').count.should eq 5
103
+ end
104
+
105
+ it 'shows some pages when there are 20', js: true do
106
+ 20.times do |i|
107
+ Product.create!
108
+ end
109
+ visit one_item_per_page_with_pagination_products_path
110
+ pages = page.all('.pagination li a').map{|a| a['data-page'].to_i}
111
+ pages.should eq [1,2,3,10,20]
112
+ end
113
+ end
114
+ context 'pagination setting is false' do
115
+ it 'has no pages', js: true do
116
+ 5.times do |i|
117
+ Product.create!
118
+ end
119
+ visit one_item_per_page_without_pagination_products_path
120
+ page.all('.pagination li a').count.should be 0
121
+ end
122
+ end
123
+ end
124
+
125
+ describe "Filters", js: true do
126
+ it "filters with like" do
127
+ names.each do |n|
128
+ Product.create!(:title => n, :active => true, :price => 10.0)
129
+ end
130
+ visit simple_index_products_path
131
+ find('.icon-filter').trigger('click')
132
+ fill_in("product_filter[title][like]", :with => "ore")
133
+ click_button("Apply")
134
+ sleep(2)
135
+ page.should have_content("lorem")
136
+ page.should have_content("labore")
137
+ page.should have_content("dolore")
138
+ find('.icon-filter').trigger('click')
139
+ fill_in("product_filter[title][like]", :with => "loreem")
140
+ click_button("Apply")
141
+ page.should_not have_content("lorem")
142
+ end
143
+
144
+ it "filters" do
145
+ Product.create!([{title: 'foo', vendor: @vendor1},
146
+ {title: 'bar', vendor: @vendor2}])
147
+ visit simple_index_products_path
148
+ find('.icon-filter').trigger('click')
149
+ fill_in("product_filter[__association][vendor.name]", :with => 'producer')
150
+ click_button("Apply")
151
+ page.should have_content(@vendor2.name)
152
+ page.should_not have_content(@vendor1.name)
153
+ end
154
+
155
+ it "filters with range", js: true do
156
+ n = names.length
157
+ Product.create!([{title: 'foo', price: 5}, {title: 'bar', price: 17}])
158
+ visit simple_index_products_path
159
+ find('.icon-filter').trigger('click')
160
+ page.save_screenshot('/Users/crunch/Desktop/file.png')
161
+ within('form.tabulatr_filter_form') do
162
+ fill_in("product_filter[price][from]", :with => 4)
163
+ fill_in("product_filter[price][to]", :with => 10)
164
+ end
165
+ click_button("Apply")
166
+ page.should have_content('foo')
167
+ page.should_not have_content('bar')
168
+ find('.icon-filter').trigger('click')
169
+ fill_in("product_filter[price][from]", :with => 12)
170
+ fill_in("product_filter[price][to]", :with => 19)
171
+ click_button("Apply")
172
+ page.should have_content('bar')
173
+ page.should_not have_content('foo')
174
+ end
175
+ end
176
+
177
+ describe "Sorting" do
178
+ it "knows how to sort", js: true do
179
+ names.each do |n|
180
+ Product.create!(title: n, vendor: @vendor1, active: true, price: 10.0)
181
+ end
182
+ Product.count.should > 10
183
+ visit simple_index_products_path
184
+ (1..10).each do |i|
185
+ page.should have_content names[i-1]
186
+ end
187
+ find("#product_sort_title").trigger('click')
188
+ snames = names.sort
189
+ (1..10).each do |i|
190
+ page.should have_content snames[-i]
191
+ end
192
+ find("#product_sort_title").trigger('click')
193
+ (1..10).each do |i|
194
+ page.should have_content snames[i-1]
195
+ end
196
+ end
197
+ end
198
+
199
+ describe "Show simple records" do
200
+
201
+ it "contains the actual data", js: false do
202
+ names.shuffle.each.with_index do |n,i|
203
+ p = Product.new(:title => n, :active => true, :price => 10.0 + i)
204
+ p.vendor = [@vendor1, @vendor2].shuffle.first
205
+ p.tags = [@tag1, @tag2, @tag3].shuffle[0..rand(3)]
206
+ p.save!
207
+ end
208
+ visit stupid_array_products_path
209
+ Product.order('price asc').limit(11).each do |product|
210
+ page.should have_content(product.title)
211
+ page.should have_content(product.title.upcase)
212
+ page.should have_content(product.price)
213
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content(product.vendor.name)
214
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content(product.title)
215
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content("foo#{product.title}foo")
216
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content("bar#{product.title}bar")
217
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content("%08.4f" % product.price)
218
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content(product.tags.count)
219
+ product.tags.each do |tag|
220
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content(tag.title)
221
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content("foo#{tag.title}foo")
222
+ find(".tabulatr_table tbody #product_#{product.id}").should have_content("bar#{tag.title}bar")
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ class Example
5
+ end
6
+
7
+ describe Tabulatr::Finder do
8
+ describe '.find_for_table' do
9
+ before(:each) do
10
+ Tabulatr::Security.stub(:validate!){ true }
11
+ end
12
+
13
+ context 'descends_from_activerecord' do
14
+ it 'works fine' do
15
+ expect{ subject.find_for_table(Product, {})}.to_not raise_error
16
+ end
17
+ end
18
+
19
+ context 'doesn\'t descend_from_activerecord' do
20
+ it 'raises an exception' do
21
+ expect{ subject.find_for_table(Example, {})}.to raise_error
22
+ end
23
+ end
24
+
25
+ it 'defines some methods' do
26
+ result = subject.find_for_table(Product, {})
27
+ result.should respond_to :__pagination
28
+ result.should respond_to :to_tabulatr_json
29
+ end
30
+
31
+ it 'orders the result' do
32
+ p1 = Product.create!(title: 'abc')
33
+ p2 = Product.create!(title: 'mno')
34
+ result = subject.find_for_table(Product, {
35
+ sort_by: :title,
36
+ orientation: :asc,
37
+ arguments: 'id,title'
38
+ }).to_tabulatr_json
39
+ result[:data].length.should eq 2
40
+ result[:data].first['id'].should eq p1.id
41
+ result[:data].last['id'].should eq p2.id
42
+ result = subject.find_for_table(Product, {
43
+ sort_by: :title,
44
+ orientation: :desc,
45
+ arguments: 'id,title'
46
+ }).to_tabulatr_json
47
+ result[:data].length.should eq 2
48
+ result[:data].first['id'].should eq p2.id
49
+ result[:data].last['id'].should eq p1.id
50
+ end
51
+
52
+ it 'limits the result' do
53
+ 3.times do |p|
54
+ Product.create!
55
+ end
56
+ result = subject.find_for_table(Product, {
57
+ arguments: 'id',
58
+ pagesize: 2
59
+ }).to_tabulatr_json
60
+ Product.count.should eq 3
61
+ result[:data].count.should eq 2
62
+ end
63
+
64
+ context 'page parameter not given' do
65
+ it 'defaults to the first page' do
66
+ result = subject.find_for_table(Product, {})
67
+ result.__pagination[:page].should eq 1
68
+ end
69
+ end
70
+
71
+ context 'page parameter is given' do
72
+ it 'uses it' do
73
+ result = subject.find_for_table(Product, {
74
+ page: 3
75
+ })
76
+ result.__pagination[:page].should eq 3
77
+ end
78
+ end
79
+
80
+ context 'append is "false"' do
81
+ it 'converts from string to boolean' do
82
+ result = subject.find_for_table(Product, {
83
+ append: 'false',
84
+ arguments: 'title'
85
+ })
86
+ result.__pagination[:append].should be_false
87
+ end
88
+ end
89
+
90
+ context 'append is "true"' do
91
+ it 'converts from string to boolean' do
92
+ result = subject.find_for_table(Product, {
93
+ append: 'true',
94
+ arguments: 'title'
95
+ })
96
+ result.__pagination[:append].should be_true
97
+ end
98
+ end
99
+
100
+ it 'filters the data' do
101
+ # article_filter[body][like]:test
102
+ p1 = Product.create!(title: 'foobar')
103
+ p2 = Product.create!(title: 'buzz')
104
+ result = subject.find_for_table(Product, {
105
+ arguments: 'title',
106
+ 'product_filter' => {
107
+ 'title' => {
108
+ like: 'buz'
109
+ }
110
+ }
111
+ }).to_tabulatr_json
112
+ Product.count.should eq 2
113
+ result[:data].count.should eq 1
114
+ expect(result[:data].first[:id]).to eq(p2.id)
115
+ end
116
+
117
+ it 'filters the data with belongs_to filter' do
118
+ v = Vendor.create!(name: 'vnd')
119
+ v2 = Vendor.create!(name: 'vnd_two')
120
+ p1 = Product.create!(title: 'foobar', vendor: v)
121
+ p2 = Product.create!(title: 'buzz', vendor: v2)
122
+ result = subject.find_for_table(Product, {
123
+ arguments: 'title,vendor:name',
124
+ 'product_filter' => {
125
+ '__association' => {
126
+ 'vendor.name' => 'vnd'
127
+ }
128
+ }
129
+ }).to_tabulatr_json
130
+ Product.count.should eq 2
131
+ Vendor.count.should eq 2
132
+ result[:data].count.should eq 1
133
+ expect(result[:data].first[:id]).to eq(p1.id)
134
+ end
135
+
136
+ it 'filters the data with has_many filter' do
137
+ t = Tag.create!(title: 'keyword')
138
+ t2 = Tag.create!(title: 'cloud')
139
+ p1 = Product.create!(title: 'foobar')
140
+ p2 = Product.create!(title: 'buzz')
141
+ p1.tags << t
142
+ p1.save!
143
+ p2.tags << t2
144
+ p2.save!
145
+ result = subject.find_for_table(Product, {
146
+ arguments: 'tags:title',
147
+ 'product_filter' => {
148
+ '__association' => {
149
+ 'tags.title' => 'cloud'
150
+ }
151
+ }
152
+ }).to_tabulatr_json
153
+ Product.count.should eq 2
154
+ Tag.count.should eq 2
155
+ result[:data].count.should eq 1
156
+ expect(result[:data].first[:id]).to eq(p2.id)
157
+ end
158
+
159
+ it 'invokes given batch actions' do
160
+ p1 = Product.create!(title: 'foobar')
161
+ p2 = Product.create!(title: 'buz')
162
+ expect{ |b| subject.find_for_table(Product, {
163
+ 'product_batch' => {
164
+ foo: ''
165
+ },
166
+ 'tabulatr_checked' => {
167
+ checked_ids: '1,2'
168
+ }
169
+ }, &b)
170
+ }.to yield_control
171
+ end
172
+
173
+ it 'doesn\'t invoke when there are no batch actions' do
174
+ p1 = Product.create!(title: 'foobar')
175
+ p2 = Product.create!(title: 'buz')
176
+ expect{ |b| subject.find_for_table(Product, {}, &b)}
177
+ .to_not yield_control
178
+ end
179
+ end
180
+
181
+ describe '.build_offset' do
182
+ it 'figures the correct number of pages' do
183
+ pages = Tabulatr::Finder.build_offset(1, 10, 302, {})
184
+ expect(pages[:pages]).to eq 31
185
+ end
186
+ end
187
+ end