ransack 2.3.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/SECURITY.md +12 -0
  4. data/.github/workflows/codeql.yml +72 -0
  5. data/.github/workflows/cronjob.yml +99 -0
  6. data/.github/workflows/deploy.yml +35 -0
  7. data/.github/workflows/rubocop.yml +20 -0
  8. data/.github/workflows/test-deploy.yml +29 -0
  9. data/.github/workflows/test.yml +131 -0
  10. data/.nojekyll +0 -0
  11. data/.rubocop.yml +50 -0
  12. data/CHANGELOG.md +263 -1
  13. data/CONTRIBUTING.md +51 -29
  14. data/Gemfile +24 -10
  15. data/README.md +49 -917
  16. data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +78 -0
  17. data/bug_report_templates/test-ransacker-arel-present-predicate.rb +75 -0
  18. data/docs/.gitignore +19 -0
  19. data/docs/.nojekyll +0 -0
  20. data/docs/babel.config.js +3 -0
  21. data/docs/blog/2022-03-27-ransack-3.0.0.md +20 -0
  22. data/docs/docs/getting-started/_category_.json +4 -0
  23. data/docs/docs/getting-started/advanced-mode.md +46 -0
  24. data/docs/docs/getting-started/configuration.md +47 -0
  25. data/docs/docs/getting-started/search-matches.md +67 -0
  26. data/docs/docs/getting-started/simple-mode.md +288 -0
  27. data/docs/docs/getting-started/sorting.md +71 -0
  28. data/docs/docs/getting-started/using-predicates.md +282 -0
  29. data/docs/docs/going-further/_category_.json +4 -0
  30. data/docs/docs/going-further/acts-as-taggable-on.md +114 -0
  31. data/docs/docs/going-further/associations.md +70 -0
  32. data/docs/docs/going-further/custom-predicates.md +52 -0
  33. data/docs/docs/going-further/documentation.md +43 -0
  34. data/docs/docs/going-further/exporting-to-csv.md +49 -0
  35. data/docs/docs/going-further/external-guides.md +57 -0
  36. data/docs/docs/going-further/form-customisation.md +63 -0
  37. data/docs/docs/going-further/i18n.md +53 -0
  38. data/docs/docs/going-further/img/create_release.png +0 -0
  39. data/docs/docs/going-further/merging-searches.md +41 -0
  40. data/docs/docs/going-further/other-notes.md +428 -0
  41. data/docs/docs/going-further/polymorphic-search.md +46 -0
  42. data/docs/docs/going-further/ransackers.md +331 -0
  43. data/docs/docs/going-further/release_process.md +36 -0
  44. data/docs/docs/going-further/saving-queries.md +82 -0
  45. data/docs/docs/going-further/searching-postgres.md +57 -0
  46. data/docs/docs/going-further/wiki-contributors.md +82 -0
  47. data/docs/docs/intro.md +99 -0
  48. data/docs/docusaurus.config.js +120 -0
  49. data/docs/package.json +42 -0
  50. data/docs/sidebars.js +31 -0
  51. data/docs/src/components/HomepageFeatures/index.js +64 -0
  52. data/docs/src/components/HomepageFeatures/styles.module.css +11 -0
  53. data/docs/src/css/custom.css +39 -0
  54. data/docs/src/pages/index.module.css +23 -0
  55. data/docs/src/pages/markdown-page.md +7 -0
  56. data/docs/static/.nojekyll +0 -0
  57. data/docs/static/img/docusaurus.png +0 -0
  58. data/docs/static/img/favicon.ico +0 -0
  59. data/docs/static/img/logo.svg +1 -0
  60. data/docs/static/img/tutorial/docsVersionDropdown.png +0 -0
  61. data/docs/static/img/tutorial/localeDropdown.png +0 -0
  62. data/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
  63. data/docs/static/img/undraw_docusaurus_react.svg +170 -0
  64. data/docs/static/img/undraw_docusaurus_tree.svg +40 -0
  65. data/docs/yarn.lock +8879 -0
  66. data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +70 -0
  67. data/{polyamorous/lib/polyamorous/activerecord_6.0_ruby_2 → lib/polyamorous/activerecord_6.1_ruby_2}/join_dependency.rb +33 -12
  68. data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +11 -0
  69. data/lib/polyamorous/activerecord_7.0_ruby_2/join_association.rb +1 -0
  70. data/lib/polyamorous/activerecord_7.0_ruby_2/join_dependency.rb +1 -0
  71. data/lib/polyamorous/activerecord_7.0_ruby_2/reflection.rb +1 -0
  72. data/lib/polyamorous/activerecord_7.1_ruby_2/join_association.rb +1 -0
  73. data/lib/polyamorous/activerecord_7.1_ruby_2/join_dependency.rb +1 -0
  74. data/lib/polyamorous/activerecord_7.1_ruby_2/reflection.rb +1 -0
  75. data/{polyamorous/lib → lib/polyamorous}/polyamorous.rb +3 -8
  76. data/lib/ransack/adapters/active_record/base.rb +83 -10
  77. data/lib/ransack/adapters/active_record/context.rb +61 -116
  78. data/lib/ransack/configuration.rb +53 -10
  79. data/lib/ransack/constants.rb +126 -7
  80. data/lib/ransack/context.rb +34 -5
  81. data/lib/ransack/helpers/form_builder.rb +11 -17
  82. data/lib/ransack/helpers/form_helper.rb +14 -5
  83. data/lib/ransack/helpers.rb +1 -1
  84. data/lib/ransack/locale/sk.yml +70 -0
  85. data/lib/ransack/locale/sv.yml +70 -0
  86. data/lib/ransack/nodes/attribute.rb +3 -3
  87. data/lib/ransack/nodes/condition.rb +87 -8
  88. data/lib/ransack/nodes/grouping.rb +4 -4
  89. data/lib/ransack/nodes/node.rb +1 -1
  90. data/lib/ransack/nodes/sort.rb +3 -3
  91. data/lib/ransack/nodes/value.rb +3 -3
  92. data/lib/ransack/predicate.rb +3 -2
  93. data/lib/ransack/ransacker.rb +1 -1
  94. data/lib/ransack/search.rb +15 -7
  95. data/lib/ransack/translate.rb +6 -6
  96. data/lib/ransack/version.rb +1 -1
  97. data/lib/ransack/visitor.rb +38 -2
  98. data/lib/ransack.rb +6 -10
  99. data/ransack.gemspec +9 -24
  100. data/spec/blueprints/articles.rb +1 -1
  101. data/spec/blueprints/comments.rb +1 -1
  102. data/spec/blueprints/notes.rb +1 -1
  103. data/spec/blueprints/tags.rb +1 -1
  104. data/spec/console.rb +5 -5
  105. data/spec/helpers/polyamorous_helper.rb +2 -17
  106. data/spec/helpers/ransack_helper.rb +1 -1
  107. data/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
  108. data/spec/{ransack → polyamorous}/join_association_spec.rb +3 -1
  109. data/spec/{ransack → polyamorous}/join_dependency_spec.rb +0 -16
  110. data/spec/ransack/adapters/active_record/base_spec.rb +125 -16
  111. data/spec/ransack/adapters/active_record/context_spec.rb +19 -18
  112. data/spec/ransack/configuration_spec.rb +33 -9
  113. data/spec/ransack/helpers/form_builder_spec.rb +8 -8
  114. data/spec/ransack/helpers/form_helper_spec.rb +109 -20
  115. data/spec/ransack/nodes/condition_spec.rb +37 -0
  116. data/spec/ransack/nodes/grouping_spec.rb +2 -2
  117. data/spec/ransack/nodes/value_spec.rb +115 -0
  118. data/spec/ransack/predicate_spec.rb +75 -2
  119. data/spec/ransack/search_spec.rb +239 -38
  120. data/spec/ransack/translate_spec.rb +1 -1
  121. data/spec/spec_helper.rb +9 -5
  122. data/spec/support/schema.rb +111 -12
  123. metadata +105 -195
  124. data/.travis.yml +0 -49
  125. data/lib/ransack/adapters/active_record/ransack/constants.rb +0 -116
  126. data/lib/ransack/adapters/active_record/ransack/context.rb +0 -60
  127. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +0 -61
  128. data/lib/ransack/adapters/active_record/ransack/translate.rb +0 -8
  129. data/lib/ransack/adapters/active_record/ransack/visitor.rb +0 -47
  130. data/lib/ransack/adapters.rb +0 -64
  131. data/lib/ransack/nodes.rb +0 -8
  132. data/polyamorous/lib/polyamorous/activerecord_5.0_ruby_2/join_association.rb +0 -2
  133. data/polyamorous/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +0 -2
  134. data/polyamorous/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +0 -31
  135. data/polyamorous/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +0 -112
  136. data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +0 -31
  137. data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +0 -112
  138. data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/reflection.rb +0 -12
  139. data/polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2/join_association.rb +0 -22
  140. data/polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2/join_dependency.rb +0 -81
  141. data/polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2/reflection.rb +0 -2
  142. data/polyamorous/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +0 -2
  143. data/polyamorous/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +0 -2
  144. data/polyamorous/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +0 -2
  145. data/polyamorous/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +0 -2
  146. data/polyamorous/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +0 -2
  147. data/polyamorous/lib/polyamorous/version.rb +0 -3
  148. data/polyamorous/polyamorous.gemspec +0 -35
  149. /data/{logo → docs/static/logo}/ransack-h.png +0 -0
  150. /data/{logo → docs/static/logo}/ransack-h.svg +0 -0
  151. /data/{logo → docs/static/logo}/ransack-v.png +0 -0
  152. /data/{logo → docs/static/logo}/ransack-v.svg +0 -0
  153. /data/{logo → docs/static/logo}/ransack.png +0 -0
  154. /data/{logo → docs/static/logo}/ransack.svg +0 -0
  155. /data/{polyamorous/lib → lib}/polyamorous/join.rb +0 -0
  156. /data/{polyamorous/lib → lib}/polyamorous/swapping_reflection_class.rb +0 -0
  157. /data/{polyamorous/lib → lib}/polyamorous/tree_node.rb +0 -0
  158. /data/lib/ransack/{adapters/active_record.rb → active_record.rb} +0 -0
  159. /data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
@@ -140,6 +140,32 @@ module Ransack
140
140
  }
141
141
  end
142
142
 
143
+ describe '#sort_link works even if search params are a string' do
144
+ before { @controller.view_context.params[:q] = 'input error' }
145
+ specify {
146
+ expect { @controller.view_context
147
+ .sort_link(
148
+ Person.ransack({}),
149
+ :name,
150
+ controller: 'people'
151
+ )
152
+ }.not_to raise_error
153
+ }
154
+ end
155
+
156
+ describe '#sort_url works even if search params are a string' do
157
+ before { @controller.view_context.params[:q] = 'input error' }
158
+ specify {
159
+ expect { @controller.view_context
160
+ .sort_url(
161
+ Person.ransack({}),
162
+ :name,
163
+ controller: 'people'
164
+ )
165
+ }.not_to raise_error
166
+ }
167
+ end
168
+
143
169
  describe '#sort_link with search_key defined as a string' do
144
170
  subject { @controller.view_context
145
171
  .sort_link(
@@ -186,7 +212,7 @@ module Ransack
186
212
  )
187
213
  }
188
214
  it {
189
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
215
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
190
216
  )
191
217
  }
192
218
  it { should match /sort_link desc/ }
@@ -202,7 +228,7 @@ module Ransack
202
228
  )
203
229
  }
204
230
  it {
205
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
231
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
206
232
  )
207
233
  }
208
234
  end
@@ -216,7 +242,7 @@ module Ransack
216
242
  )
217
243
  }
218
244
  it {
219
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
245
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
220
246
  )
221
247
  }
222
248
  it { should match /sort_link desc/ }
@@ -232,7 +258,7 @@ module Ransack
232
258
  )
233
259
  }
234
260
  it {
235
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
261
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
236
262
  )
237
263
  }
238
264
  end
@@ -258,7 +284,7 @@ module Ransack
258
284
  )
259
285
  }
260
286
  it {
261
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
287
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
262
288
  )
263
289
  }
264
290
  it { should match /sort_link desc/ }
@@ -274,7 +300,7 @@ module Ransack
274
300
  )
275
301
  }
276
302
  it {
277
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
303
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
278
304
  )
279
305
  }
280
306
  end
@@ -289,7 +315,7 @@ module Ransack
289
315
  )
290
316
  }
291
317
  it {
292
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
318
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
293
319
  )
294
320
  }
295
321
  it { should match /sort_link/ }
@@ -306,7 +332,7 @@ module Ransack
306
332
  )
307
333
  }
308
334
  it {
309
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
335
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
310
336
  )
311
337
  }
312
338
  end
@@ -321,7 +347,7 @@ module Ransack
321
347
  )
322
348
  }
323
349
  it {
324
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
350
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
325
351
  )
326
352
  }
327
353
  it { should match /sort_link/ }
@@ -338,7 +364,7 @@ module Ransack
338
364
  )
339
365
  }
340
366
  it {
341
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
367
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
342
368
  )
343
369
  }
344
370
  end
@@ -353,7 +379,7 @@ module Ransack
353
379
  )
354
380
  }
355
381
  it {
356
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+asc/
382
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+asc/
357
383
  )
358
384
  }
359
385
  it { should match /sort_link/ }
@@ -370,7 +396,7 @@ module Ransack
370
396
  )
371
397
  }
372
398
  it {
373
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+asc/
399
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+asc/
374
400
  )
375
401
  }
376
402
  end
@@ -385,7 +411,7 @@ module Ransack
385
411
  )
386
412
  }
387
413
  it {
388
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
414
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
389
415
  )
390
416
  }
391
417
  it { should match /sort_link/ }
@@ -402,7 +428,7 @@ module Ransack
402
428
  )
403
429
  }
404
430
  it {
405
- should match( /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
431
+ should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
406
432
  )
407
433
  }
408
434
  end
@@ -469,13 +495,12 @@ module Ransack
469
495
  it { should match /exist\=existing/ }
470
496
  end
471
497
 
472
- context 'using a real ActionController::Parameter object',
473
- if: ::ActiveRecord::VERSION::MAJOR > 3 do
498
+ context 'using a real ActionController::Parameter object' do
474
499
 
475
500
  describe 'with symbol q:, #sort_link should include search params' do
476
501
  subject { @controller.view_context.sort_link(Person.ransack, :name) }
477
502
  let(:params) { ActionController::Parameters.new(
478
- { :q => { name_eq: 'TEST' }, controller: 'people' }
503
+ { q: { name_eq: 'TEST' }, controller: 'people' }
479
504
  ) }
480
505
  before { @controller.instance_variable_set(:@params, params) }
481
506
 
@@ -490,7 +515,7 @@ module Ransack
490
515
  describe 'with symbol q:, #sort_url should include search params' do
491
516
  subject { @controller.view_context.sort_url(Person.ransack, :name) }
492
517
  let(:params) { ActionController::Parameters.new(
493
- { :q => { name_eq: 'TEST' }, controller: 'people' }
518
+ { q: { name_eq: 'TEST' }, controller: 'people' }
494
519
  ) }
495
520
  before { @controller.instance_variable_set(:@params, params) }
496
521
 
@@ -643,13 +668,13 @@ module Ransack
643
668
  before do
644
669
  Ransack.configure do |c|
645
670
  c.hide_sort_order_indicators = false
646
- c.custom_arrows = { default_arrow: "defaultarrow"}
671
+ c.custom_arrows = { default_arrow: "defaultarrow" }
647
672
  end
648
673
  end
649
674
 
650
675
  after do
651
676
  Ransack.configure do |c|
652
- c.custom_arrows = { default_arrow: nil}
677
+ c.custom_arrows = { default_arrow: nil }
653
678
  end
654
679
  end
655
680
 
@@ -727,6 +752,70 @@ module Ransack
727
752
  it { should match /Block label ▼/ }
728
753
  end
729
754
 
755
+ describe '#sort_link with class option' do
756
+ subject { @controller.view_context
757
+ .sort_link(
758
+ [:main_app, Person.ransack(sorts: ['name desc'])],
759
+ :name,
760
+ class: 'people', controller: 'people'
761
+ )
762
+ }
763
+ it { should match /class="sort_link desc people"/ }
764
+ it { should_not match /people\?class=people/ }
765
+ end
766
+
767
+ describe '#sort_link with class option workaround' do
768
+ it "generates a correct link and prints a deprecation" do
769
+ expect do
770
+ link = @controller.view_context
771
+ .sort_link(
772
+ [:main_app, Person.ransack(sorts: ['name desc'])],
773
+ :name,
774
+ 'name',
775
+ { controller: 'people' },
776
+ class: 'people'
777
+ )
778
+
779
+ expect(link).to match(/class="sort_link desc people"/)
780
+ expect(link).not_to match(/people\?class=people/)
781
+ end.to output(
782
+ /Passing two trailing hashes to `sort_link` is deprecated, merge the trailing hashes into a single one\. \(called at #{Regexp.escape(__FILE__)}:/
783
+ ).to_stderr
784
+ end
785
+ end
786
+
787
+ describe '#sort_link with data option' do
788
+ subject { @controller.view_context
789
+ .sort_link(
790
+ [:main_app, Person.ransack(sorts: ['name desc'])],
791
+ :name,
792
+ data: { turbo_action: :advance }, controller: 'people'
793
+ )
794
+ }
795
+ it { should match /data-turbo-action="advance"/ }
796
+ it { should_not match /people\?data%5Bturbo_action%5D=advance/ }
797
+ end
798
+
799
+ describe "#sort_link with host option" do
800
+ subject { @controller.view_context
801
+ .sort_link(
802
+ [:main_app, Person.ransack(sorts: ['name desc'])],
803
+ :name,
804
+ host: 'foo', controller: 'people'
805
+ )
806
+ }
807
+ it { should match /href="\/people\?q/ }
808
+ it { should_not match /href=".*foo/ }
809
+ end
810
+
811
+ describe "#sort_link ignores host in params" do
812
+ before { @controller.view_context.params[:host] = 'other_domain' }
813
+ subject { @controller.view_context.sort_link(Person.ransack, :name, controller: 'people') }
814
+
815
+ it { should match /href="\/people\?q/ }
816
+ it { should_not match /href=".*other_domain/ }
817
+ end
818
+
730
819
  describe '#search_form_for with default format' do
731
820
  subject { @controller.view_context
732
821
  .search_form_for(Person.ransack) {} }
@@ -3,6 +3,19 @@ require 'spec_helper'
3
3
  module Ransack
4
4
  module Nodes
5
5
  describe Condition do
6
+ context 'bug report #1245' do
7
+ it 'preserves tuple behavior' do
8
+ ransack_hash = {
9
+ m: 'and',
10
+ g: [
11
+ { title_type_in: ['["title 1", ""]'] }
12
+ ]
13
+ }
14
+
15
+ sql = Article.ransack(ransack_hash).result.to_sql
16
+ expect(sql).to include("IN (('title 1', ''))")
17
+ end
18
+ end
6
19
 
7
20
  context 'with an alias' do
8
21
  subject {
@@ -61,6 +74,30 @@ module Ransack
61
74
  specify { expect(subject).to be_nil }
62
75
  end
63
76
  end
77
+
78
+ context 'with an empty predicate' do
79
+ subject {
80
+ Condition.extract(
81
+ Context.for(Person), 'full_name', Person.first.name
82
+ )
83
+ }
84
+
85
+ context "when default_predicate = nil" do
86
+ before do
87
+ Ransack.configure { |c| c.default_predicate = nil }
88
+ end
89
+
90
+ specify { expect(subject).to be_nil }
91
+ end
92
+
93
+ context "when default_predicate = 'eq'" do
94
+ before do
95
+ Ransack.configure { |c| c.default_predicate = 'eq' }
96
+ end
97
+
98
+ specify { expect(subject).to eq Condition.extract(Context.for(Person), 'full_name_eq', Person.first.name) }
99
+ end
100
+ end
64
101
  end
65
102
  end
66
103
  end
@@ -80,7 +80,7 @@ module Ransack
80
80
  'a' => {
81
81
  '0' => {
82
82
  'name' => 'with_arguments',
83
- 'ransacker_args' => [1,2]
83
+ 'ransacker_args' => [1, 2]
84
84
  }
85
85
  },
86
86
  'p' => 'eq',
@@ -90,7 +90,7 @@ module Ransack
90
90
  'a' => {
91
91
  '0' => {
92
92
  'name' => 'with_arguments',
93
- 'ransacker_args' => [3,4]
93
+ 'ransacker_args' => [3, 4]
94
94
  }
95
95
  },
96
96
  'p' => 'eq',
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+
3
+ module Ransack
4
+ module Nodes
5
+ describe Value do
6
+ let(:context) { Context.for(Person) }
7
+
8
+ subject do
9
+ Value.new(context, raw_value)
10
+ end
11
+
12
+ context "with a date value" do
13
+ let(:raw_value) { "2022-05-23" }
14
+
15
+ [:date].each do |type|
16
+ it "should cast #{type} correctly" do
17
+ result = subject.cast(type)
18
+
19
+ expect(result).to be_a_kind_of(Date)
20
+ expect(result).to eq(Date.parse(raw_value))
21
+ end
22
+ end
23
+ end
24
+
25
+ context "with a timestamp value" do
26
+ let(:raw_value) { "2022-05-23 10:40:02 -0400" }
27
+
28
+ [:datetime, :timestamp, :time, :timestamptz].each do |type|
29
+ it "should cast #{type} correctly" do
30
+ result = subject.cast(type)
31
+
32
+ expect(result).to be_a_kind_of(Time)
33
+ expect(result).to eq(Time.zone.parse(raw_value))
34
+ end
35
+ end
36
+ end
37
+
38
+ Constants::TRUE_VALUES.each do |value|
39
+ context "with a true boolean value (#{value})" do
40
+ let(:raw_value) { value.to_s }
41
+
42
+ it "should cast boolean correctly" do
43
+ result = subject.cast(:boolean)
44
+ expect(result).to eq(true)
45
+ end
46
+ end
47
+ end
48
+
49
+ Constants::FALSE_VALUES.each do |value|
50
+ context "with a false boolean value (#{value})" do
51
+ let(:raw_value) { value.to_s }
52
+
53
+ it "should cast boolean correctly" do
54
+ result = subject.cast(:boolean)
55
+
56
+ expect(result).to eq(false)
57
+ end
58
+ end
59
+ end
60
+
61
+ ["12", "101.5"].each do |value|
62
+ context "with an integer value (#{value})" do
63
+ let(:raw_value) { value }
64
+
65
+ it "should cast #{value} to integer correctly" do
66
+ result = subject.cast(:integer)
67
+
68
+ expect(result).to be_an(Integer)
69
+ expect(result).to eq(value.to_i)
70
+ end
71
+ end
72
+ end
73
+
74
+ ["12", "101.5"].each do |value|
75
+ context "with a float value (#{value})" do
76
+ let(:raw_value) { value }
77
+
78
+ it "should cast #{value} to float correctly" do
79
+ result = subject.cast(:float)
80
+
81
+ expect(result).to be_an(Float)
82
+ expect(result).to eq(value.to_f)
83
+ end
84
+ end
85
+ end
86
+
87
+ ["12", "101.5"].each do |value|
88
+ context "with a decimal value (#{value})" do
89
+ let(:raw_value) { value }
90
+
91
+ it "should cast #{value} to decimal correctly" do
92
+ result = subject.cast(:decimal)
93
+
94
+ expect(result).to be_a(BigDecimal)
95
+ expect(result).to eq(value.to_d)
96
+ end
97
+ end
98
+ end
99
+
100
+ ["12", "101.513"].each do |value|
101
+ context "with a money value (#{value})" do
102
+ let(:raw_value) { value }
103
+
104
+ it "should cast #{value} to money correctly" do
105
+ result = subject.cast(:money)
106
+
107
+ expect(result).to be_a(String)
108
+ expect(result).to eq(value.to_f.to_s)
109
+ end
110
+ end
111
+ end
112
+
113
+ end
114
+ end
115
+ end
@@ -35,6 +35,13 @@ module Ransack
35
35
  @s.awesome_eq = nil
36
36
  expect(@s.result.to_sql).not_to match /WHERE/
37
37
  end
38
+
39
+ it 'generates a = condition with a huge integer value' do
40
+ val = 123456789012345678901
41
+ @s.salary_eq = val
42
+ field = "#{quote_table_name("people")}.#{quote_column_name("salary")}"
43
+ expect(@s.result.to_sql).to match /#{field} = #{val}/
44
+ end
38
45
  end
39
46
 
40
47
  describe 'lteq' do
@@ -56,6 +63,13 @@ module Ransack
56
63
  @s.salary_lteq = nil
57
64
  expect(@s.result.to_sql).not_to match /WHERE/
58
65
  end
66
+
67
+ it 'generates a <= condition with a huge integer value' do
68
+ val = 123456789012345678901
69
+ @s.salary_lteq = val
70
+ field = "#{quote_table_name("people")}.#{quote_column_name("salary")}"
71
+ expect(@s.result.to_sql).to match /#{field} <= #{val}/
72
+ end
59
73
  end
60
74
 
61
75
  describe 'lt' do
@@ -77,6 +91,13 @@ module Ransack
77
91
  @s.salary_lt = nil
78
92
  expect(@s.result.to_sql).not_to match /WHERE/
79
93
  end
94
+
95
+ it 'generates a = condition with a huge integer value' do
96
+ val = 123456789012345678901
97
+ @s.salary_lt = val
98
+ field = "#{quote_table_name("people")}.#{quote_column_name("salary")}"
99
+ expect(@s.result.to_sql).to match /#{field} < #{val}/
100
+ end
80
101
  end
81
102
 
82
103
  describe 'gteq' do
@@ -98,6 +119,13 @@ module Ransack
98
119
  @s.salary_gteq = nil
99
120
  expect(@s.result.to_sql).not_to match /WHERE/
100
121
  end
122
+
123
+ it 'generates a >= condition with a huge integer value' do
124
+ val = 123456789012345678901
125
+ @s.salary_gteq = val
126
+ field = "#{quote_table_name("people")}.#{quote_column_name("salary")}"
127
+ expect(@s.result.to_sql).to match /#{field} >= #{val}/
128
+ end
101
129
  end
102
130
 
103
131
  describe 'gt' do
@@ -119,6 +147,13 @@ module Ransack
119
147
  @s.salary_gt = nil
120
148
  expect(@s.result.to_sql).not_to match /WHERE/
121
149
  end
150
+
151
+ it 'generates a > condition with a huge integer value' do
152
+ val = 123456789012345678901
153
+ @s.salary_gt = val
154
+ field = "#{quote_table_name("people")}.#{quote_column_name("salary")}"
155
+ expect(@s.result.to_sql).to match /#{field} > #{val}/
156
+ end
122
157
  end
123
158
 
124
159
  describe 'cont' do
@@ -159,6 +194,44 @@ module Ransack
159
194
  end
160
195
  end
161
196
 
197
+ describe 'i_cont' do
198
+ it_has_behavior 'wildcard escaping', :name_i_cont,
199
+ (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
200
+ /"people"."name" ILIKE '%\\%\\.\\_\\\\%'/
201
+ elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
202
+ /LOWER\(`people`.`name`\) LIKE '%\\\\%.\\\\_\\\\\\\\%'/
203
+ else
204
+ /LOWER\("people"."name"\) LIKE '%%._\\%'/
205
+ end) do
206
+ subject { @s }
207
+ end
208
+
209
+ it 'generates a LIKE query with LOWER(column) and value surrounded by %' do
210
+ @s.name_i_cont = 'Ric'
211
+ field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
212
+ expect(@s.result.to_sql).to match /[LOWER\(]?#{field}\)? I?LIKE '%ric%'/
213
+ end
214
+ end
215
+
216
+ describe 'not_i_cont' do
217
+ it_has_behavior 'wildcard escaping', :name_not_i_cont,
218
+ (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
219
+ /"people"."name" NOT ILIKE '%\\%\\.\\_\\\\%'/
220
+ elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
221
+ /LOWER\(`people`.`name`\) NOT LIKE '%\\\\%.\\\\_\\\\\\\\%'/
222
+ else
223
+ /LOWER\("people"."name"\) NOT LIKE '%%._\\%'/
224
+ end) do
225
+ subject { @s }
226
+ end
227
+
228
+ it 'generates a NOT LIKE query with LOWER(column) and value surrounded by %' do
229
+ @s.name_not_i_cont = 'Ric'
230
+ field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
231
+ expect(@s.result.to_sql).to match /[LOWER\(]?#{field}\)? NOT I?LIKE '%ric%'/
232
+ end
233
+ end
234
+
162
235
  describe 'start' do
163
236
  it 'generates a LIKE query with value followed by %' do
164
237
  @s.name_start = 'Er'
@@ -330,7 +403,7 @@ module Ransack
330
403
  expect(@s.result.to_sql).to match /#{field} IS NULL/
331
404
  end
332
405
 
333
- describe 'with association qeury' do
406
+ describe 'with association query' do
334
407
  it 'generates a value IS NOT NULL query' do
335
408
  @s.comments_id_not_null = true
336
409
  sql = @s.result.to_sql
@@ -384,7 +457,7 @@ module Ransack
384
457
  context "defining custom predicates" do
385
458
  describe "with 'not_in' arel predicate" do
386
459
  before do
387
- Ransack.configure {|c| c.add_predicate "not_in_csv", arel_predicate: "not_in", formatter: proc { |v| v.split(",") } }
460
+ Ransack.configure { |c| c.add_predicate "not_in_csv", arel_predicate: "not_in", formatter: proc { |v| v.split(",") } }
388
461
  end
389
462
 
390
463
  it 'generates a value IS NOT NULL query' do