ransack 2.3.0 → 4.0.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 +102 -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 +128 -0
  10. data/.nojekyll +0 -0
  11. data/.rubocop.yml +47 -0
  12. data/CHANGELOG.md +228 -1
  13. data/CONTRIBUTING.md +47 -22
  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 +79 -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 +40 -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 +8790 -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 +23 -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 +59 -115
  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 +109 -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 +83 -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
@@ -8,7 +8,6 @@ module Ransack
8
8
  subject { ::ActiveRecord::Base }
9
9
 
10
10
  it { should respond_to :ransack }
11
- it { should respond_to :search }
12
11
 
13
12
  describe '#search' do
14
13
  subject { Person.ransack }
@@ -44,12 +43,12 @@ module Ransack
44
43
 
45
44
  it 'applies stringy boolean scopes with true value in an array' do
46
45
  s = Person.ransack('of_age' => ['true'])
47
- expect(s.result.to_sql).to (include 'age >= 18')
46
+ expect(s.result.to_sql).to (include rails7_and_mysql ? %q{(age >= '18')} : 'age >= 18')
48
47
  end
49
48
 
50
49
  it 'applies stringy boolean scopes with false value in an array' do
51
50
  s = Person.ransack('of_age' => ['false'])
52
- expect(s.result.to_sql).to (include 'age < 18')
51
+ expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age < '18'} : 'age < 18')
53
52
  end
54
53
 
55
54
  it 'ignores unlisted scopes' do
@@ -69,15 +68,25 @@ module Ransack
69
68
 
70
69
  it 'passes values to scopes' do
71
70
  s = Person.ransack('over_age' => 18)
72
- expect(s.result.to_sql).to (include 'age > 18')
71
+ expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '18'} : 'age > 18')
73
72
  end
74
73
 
75
74
  it 'chains scopes' do
76
75
  s = Person.ransack('over_age' => 18, 'active' => true)
77
- expect(s.result.to_sql).to (include 'age > 18')
76
+ expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '18'} : 'age > 18')
78
77
  expect(s.result.to_sql).to (include 'active = 1')
79
78
  end
80
79
 
80
+ it 'applies scopes that define string SQL joins' do
81
+ allow(Article)
82
+ .to receive(:ransackable_scopes)
83
+ .and_return([:latest_comment_cont])
84
+
85
+ # Including a negative condition to test removing the scope
86
+ s = Search.new(Article, notes_note_not_eq: 'Test', latest_comment_cont: 'Test')
87
+ expect(s.result.to_sql).to include 'latest_comment'
88
+ end
89
+
81
90
  context "with sanitize_custom_scope_booleans set to false" do
82
91
  before(:all) do
83
92
  Ransack.configure { |c| c.sanitize_custom_scope_booleans = false }
@@ -89,12 +98,12 @@ module Ransack
89
98
 
90
99
  it 'passes true values to scopes' do
91
100
  s = Person.ransack('over_age' => 1)
92
- expect(s.result.to_sql).to (include 'age > 1')
101
+ expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '1'} : 'age > 1')
93
102
  end
94
103
 
95
104
  it 'passes false values to scopes' do
96
105
  s = Person.ransack('over_age' => 0)
97
- expect(s.result.to_sql).to (include 'age > 0')
106
+ expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '0'} : 'age > 0')
98
107
  end
99
108
  end
100
109
 
@@ -107,12 +116,12 @@ module Ransack
107
116
 
108
117
  it 'passes true values to scopes' do
109
118
  s = Person.ransack('over_age' => 1)
110
- expect(s.result.to_sql).to (include 'age > 1')
119
+ expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '1'} : 'age > 1')
111
120
  end
112
121
 
113
122
  it 'passes false values to scopes' do
114
123
  s = Person.ransack('over_age' => 0)
115
- expect(s.result.to_sql).to (include 'age > 0')
124
+ expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '0'} : 'age > 0')
116
125
  end
117
126
  end
118
127
 
@@ -122,6 +131,10 @@ module Ransack
122
131
  expect { Person.ransack('') }.to_not raise_error
123
132
  end
124
133
 
134
+ it 'raises exception if ransack! called with unknown condition' do
135
+ expect { Person.ransack!(unknown_attr_eq: 'Ernie') }.to raise_error(ArgumentError)
136
+ end
137
+
125
138
  it 'does not modify the parameters' do
126
139
  params = { name_eq: '' }
127
140
  expect { Person.ransack(params) }.not_to change { params }
@@ -143,14 +156,12 @@ module Ransack
143
156
  it 'removes redundant joins from top query' do
144
157
  s = Article.ransack(tags_name_not_eq: "Fantasy")
145
158
  sql = s.result.to_sql
146
-
147
159
  expect(sql).to_not include('LEFT OUTER JOIN')
148
160
  end
149
161
 
150
162
  it 'handles != for single values' do
151
163
  s = Article.ransack(tags_name_not_eq: "Fantasy")
152
164
  articles = s.result.to_a
153
-
154
165
  expect(articles).to include marco
155
166
  expect(articles).to_not include arthur
156
167
  end
@@ -267,10 +278,12 @@ module Ransack
267
278
  # end
268
279
 
269
280
  it 'creates ransack attributes' do
281
+ person = Person.create!(name: 'Aric Smith')
282
+
270
283
  s = Person.ransack(reversed_name_eq: 'htimS cirA')
271
284
  expect(s.result.size).to eq(1)
272
285
 
273
- expect(s.result.first).to eq Person.where(name: 'Aric Smith').first
286
+ expect(s.result.first).to eq person
274
287
  end
275
288
 
276
289
  it 'can be accessed through associations' do
@@ -310,7 +323,11 @@ module Ransack
310
323
  end
311
324
 
312
325
  it 'should function correctly with a multi-parameter attribute' do
313
- ::ActiveRecord::Base.default_timezone = :utc
326
+ if ::ActiveRecord::VERSION::MAJOR >= 7
327
+ ::ActiveRecord.default_timezone = :utc
328
+ else
329
+ ::ActiveRecord::Base.default_timezone = :utc
330
+ end
314
331
  Time.zone = 'UTC'
315
332
 
316
333
  date = Date.current
@@ -460,9 +477,9 @@ module Ransack
460
477
  Comment.create(article: Article.create(title: 'Avenger'), person: Person.create(salary: 100_000)),
461
478
  Comment.create(article: Article.create(title: 'Avenge'), person: Person.create(salary: 50_000)),
462
479
  ]
463
- expect(Comment.ransack(article_title_cont: 'aven',s: 'person_salary desc').result).to eq(comments)
480
+ expect(Comment.ransack(article_title_cont: 'aven', s: 'person_salary desc').result).to eq(comments)
464
481
  expect(Comment.joins(:person).ransack(s: 'persons_salarydesc', article_title_cont: 'aven').result).to eq(comments)
465
- expect(Comment.joins(:person).ransack(article_title_cont: 'aven',s: 'persons_salary desc').result).to eq(comments)
482
+ expect(Comment.joins(:person).ransack(article_title_cont: 'aven', s: 'persons_salary desc').result).to eq(comments)
466
483
  end
467
484
 
468
485
  it 'allows sort by `only_sort` field' do
@@ -541,7 +558,6 @@ module Ransack
541
558
  )
542
559
  end
543
560
 
544
-
545
561
  it 'should allow passing ransacker arguments to a ransacker' do
546
562
  s = Person.ransack(
547
563
  c: [{
@@ -641,6 +657,37 @@ module Ransack
641
657
  it { should_not include 'only_sort' }
642
658
  it { should include 'only_admin' }
643
659
  end
660
+
661
+ context 'when not defined in model, nor in ApplicationRecord' do
662
+ subject { Article.ransackable_attributes }
663
+
664
+ it "raises a helpful error" do
665
+ without_application_record_method(:ransackable_attributes) do
666
+ expect { subject }.to raise_error(RuntimeError, /Ransack needs Article attributes explicitly allowlisted/)
667
+ end
668
+ end
669
+ end
670
+
671
+ context 'when defined only in model by delegating to super' do
672
+ subject { Article.ransackable_attributes }
673
+
674
+ around do |example|
675
+ Article.singleton_class.define_method(:ransackable_attributes) do
676
+ super(nil) - super(nil)
677
+ end
678
+
679
+ example.run
680
+ ensure
681
+ Article.singleton_class.remove_method(:ransackable_attributes)
682
+ end
683
+
684
+ it "returns the allowlist in the model, and warns" do
685
+ without_application_record_method(:ransackable_attributes) do
686
+ expect { subject }.to output(/Ransack's builtin `ransackable_attributes` method is deprecated/).to_stderr
687
+ expect(subject).to be_empty
688
+ end
689
+ end
690
+ end
644
691
  end
645
692
 
646
693
  describe '#ransortable_attributes' do
@@ -673,6 +720,37 @@ module Ransack
673
720
  it { should include 'parent' }
674
721
  it { should include 'children' }
675
722
  it { should include 'articles' }
723
+
724
+ context 'when not defined in model, nor in ApplicationRecord' do
725
+ subject { Article.ransackable_associations }
726
+
727
+ it "raises a helpful error" do
728
+ without_application_record_method(:ransackable_associations) do
729
+ expect { subject }.to raise_error(RuntimeError, /Ransack needs Article associations explicitly allowlisted/)
730
+ end
731
+ end
732
+ end
733
+
734
+ context 'when defined only in model by delegating to super' do
735
+ subject { Article.ransackable_associations }
736
+
737
+ around do |example|
738
+ Article.singleton_class.define_method(:ransackable_associations) do
739
+ super(nil) - super(nil)
740
+ end
741
+
742
+ example.run
743
+ ensure
744
+ Article.singleton_class.remove_method(:ransackable_associations)
745
+ end
746
+
747
+ it "returns the allowlist in the model, and warns" do
748
+ without_application_record_method(:ransackable_associations) do
749
+ expect { subject }.to output(/Ransack's builtin `ransackable_associations` method is deprecated/).to_stderr
750
+ expect(subject).to be_empty
751
+ end
752
+ end
753
+ end
676
754
  end
677
755
 
678
756
  describe '#ransackable_scopes' do
@@ -687,6 +765,21 @@ module Ransack
687
765
  it { should eq [] }
688
766
  end
689
767
 
768
+ private
769
+
770
+ def without_application_record_method(method)
771
+ ApplicationRecord.singleton_class.alias_method :"original_#{method}", :"#{method}"
772
+ ApplicationRecord.singleton_class.remove_method :"#{method}"
773
+
774
+ yield
775
+ ensure
776
+ ApplicationRecord.singleton_class.alias_method :"#{method}", :"original_#{method}"
777
+ ApplicationRecord.singleton_class.remove_method :"original_#{method}"
778
+ end
779
+
780
+ def rails7_and_mysql
781
+ ::ActiveRecord::VERSION::MAJOR >= 7 && ENV['DB'] == 'mysql'
782
+ end
690
783
  end
691
784
  end
692
785
  end
@@ -9,7 +9,6 @@ module Ransack
9
9
  describe Context do
10
10
  subject { Context.new(Person) }
11
11
 
12
-
13
12
  it 'has an Active Record alias tracker method' do
14
13
  expect(subject.alias_tracker)
15
14
  .to be_an ::ActiveRecord::Associations::AliasTracker
@@ -79,6 +78,25 @@ module Ransack
79
78
  expect(constraint.right.relation.name).to eql 'people'
80
79
  expect(constraint.right.name).to eql 'id'
81
80
  end
81
+
82
+ it 'build correlated subquery for multiple conditions (default scope)' do
83
+ search = Search.new(Person, { comments_body_not_eq: 'some_title' })
84
+
85
+ # Was
86
+ # SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
87
+ # SELECT "comments"."disabled" FROM "comments"
88
+ # WHERE "comments"."disabled" = "people"."id"
89
+ # AND NOT ("comments"."body" != 'some_title')
90
+ # ) ORDER BY "people"."id" DESC
91
+ # Should Be
92
+ # SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
93
+ # SELECT "comments"."person_id" FROM "comments"
94
+ # WHERE "comments"."person_id" = "people"."id"
95
+ # AND NOT ("comments"."body" != 'some_title')
96
+ # ) ORDER BY "people"."id" DESC
97
+
98
+ expect(search.result.to_sql).to match /.comments.\..person_id. = .people.\..id./
99
+ end
82
100
  end
83
101
 
84
102
  describe 'sharing context across searches' do
@@ -91,23 +109,6 @@ module Ransack
91
109
  context: shared_context)
92
110
  end
93
111
 
94
- describe '#join_associations', if: AR_version <= '4.0' do
95
- it 'returns dependent join associations for all searches run
96
- against the context' do
97
- parents, children = shared_context.join_associations
98
-
99
- expect(children.aliased_table_name).to eq "children_people"
100
- expect(parents.aliased_table_name).to eq "parents_people"
101
- end
102
-
103
- it 'can be rejoined to execute a valid query' do
104
- parents, children = shared_context.join_associations
105
-
106
- expect { Person.joins(parents).joins(children).to_a }
107
- .to_not raise_error
108
- end
109
- end
110
-
111
112
  describe '#join_sources' do
112
113
  it 'returns dependent arel join nodes for all searches run against
113
114
  the context' do
@@ -20,7 +20,7 @@ module Ransack
20
20
  Ransack.configure do |config|
21
21
  config.add_predicate(
22
22
  :test_predicate_without_compound,
23
- :compounds => false
23
+ compounds: false
24
24
  )
25
25
  end
26
26
  expect(Ransack.predicates)
@@ -45,6 +45,20 @@ module Ransack
45
45
  Ransack.options = default
46
46
  end
47
47
 
48
+ it 'should have default value for strip_whitespace' do
49
+ expect(Ransack.options[:strip_whitespace]).to eq true
50
+ end
51
+
52
+ it 'changes default search key parameter' do
53
+ default = Ransack.options.clone
54
+
55
+ Ransack.configure { |c| c.strip_whitespace = false }
56
+
57
+ expect(Ransack.options[:strip_whitespace]).to eq false
58
+
59
+ Ransack.options = default
60
+ end
61
+
48
62
  it 'should have default values for arrows' do
49
63
  expect(Ransack.options[:up_arrow]).to eq '&#9660;'
50
64
  expect(Ransack.options[:down_arrow]).to eq '&#9650;'
@@ -124,8 +138,8 @@ module Ransack
124
138
  Ransack.configure do |config|
125
139
  config.add_predicate(
126
140
  :test_array_predicate,
127
- :wants_array => true,
128
- :compounds => true
141
+ wants_array: true,
142
+ compounds: true
129
143
  )
130
144
  end
131
145
 
@@ -139,11 +153,11 @@ module Ransack
139
153
  Ransack.configure do |config|
140
154
  config.add_predicate(
141
155
  :test_in_predicate,
142
- :arel_predicate => 'in'
156
+ arel_predicate: 'in'
143
157
  )
144
158
  config.add_predicate(
145
159
  :test_not_in_predicate,
146
- :arel_predicate => 'not_in'
160
+ arel_predicate: 'not_in'
147
161
  )
148
162
  end
149
163
 
@@ -157,13 +171,13 @@ module Ransack
157
171
  Ransack.configure do |config|
158
172
  config.add_predicate(
159
173
  :test_in_predicate_no_array,
160
- :arel_predicate => 'in',
161
- :wants_array => false
174
+ arel_predicate: 'in',
175
+ wants_array: false
162
176
  )
163
177
  config.add_predicate(
164
178
  :test_not_in_predicate_no_array,
165
- :arel_predicate => 'not_in',
166
- :wants_array => false
179
+ arel_predicate: 'not_in',
180
+ wants_array: false
167
181
  )
168
182
  end
169
183
 
@@ -173,5 +187,15 @@ module Ransack
173
187
  .to eq false
174
188
  end
175
189
  end
190
+
191
+ it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
192
+ default = Ransack.options.clone
193
+
194
+ Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
195
+
196
+ expect(Ransack.options[:postgres_fields_sort_option]).to eq :nulls_first
197
+
198
+ Ransack.options = default
199
+ end
176
200
  end
177
201
  end
@@ -26,7 +26,7 @@ module Ransack
26
26
  # @s.created_at_eq = date_values # This works in Rails 4.x but not 3.x
27
27
  @s.created_at_eq = [2011, 1, 2, 3, 4, 5] # so we have to do this
28
28
  html = @f.datetime_select(
29
- :created_at_eq, :use_month_numbers => true, :include_seconds => true
29
+ :created_at_eq, use_month_numbers: true, include_seconds: true
30
30
  )
31
31
  date_values.each { |val| expect(html).to include date_select_html(val) }
32
32
  end
@@ -70,13 +70,13 @@ module Ransack
70
70
 
71
71
  describe '#sort_link' do
72
72
  it 'sort_link for ransack attribute' do
73
- sort_link = @f.sort_link :name, :controller => 'people'
73
+ sort_link = @f.sort_link :name, controller: 'people'
74
74
  expect(sort_link).to match /people\?q(%5B|\[)s(%5D|\])=name\+asc/
75
75
  expect(sort_link).to match /sort_link/
76
76
  expect(sort_link).to match /Full Name<\/a>/
77
77
  end
78
78
  it 'sort_link for common attribute' do
79
- sort_link = @f.sort_link :id, :controller => 'people'
79
+ sort_link = @f.sort_link :id, controller: 'people'
80
80
  expect(sort_link).to match /id<\/a>/
81
81
  end
82
82
  end
@@ -99,14 +99,14 @@ module Ransack
99
99
  it 'returns ransackable attributes for associations with :associations' do
100
100
  attributes = Person.ransackable_attributes +
101
101
  Article.ransackable_attributes.map { |a| "articles_#{a}" }
102
- html = @f.attribute_select(:associations => ['articles'])
102
+ html = @f.attribute_select(associations: ['articles'])
103
103
  expect(html.split(/\n/).size).to eq(attributes.size)
104
104
  attributes.each do |attribute|
105
105
  expect(html).to match /<option value="#{attribute}">/
106
106
  end
107
107
  end
108
108
  it 'returns option groups for base and associations with :associations' do
109
- html = @f.attribute_select(:associations => ['articles'])
109
+ html = @f.attribute_select(associations: ['articles'])
110
110
  [Person, Article].each do |model|
111
111
  expect(html).to match /<optgroup label="#{model}">/
112
112
  end
@@ -121,19 +121,19 @@ module Ransack
121
121
  end
122
122
  end
123
123
  it 'filters predicates with single-value :only' do
124
- html = @f.predicate_select :only => 'eq'
124
+ html = @f.predicate_select only: 'eq'
125
125
  Predicate.names.reject { |k| k =~ /^eq/ }.each do |key|
126
126
  expect(html).not_to match /<option value="#{key}">/
127
127
  end
128
128
  end
129
129
  it 'filters predicates with multi-value :only' do
130
- html = @f.predicate_select :only => [:eq, :lt]
130
+ html = @f.predicate_select only: [:eq, :lt]
131
131
  Predicate.names.reject { |k| k =~ /^(eq|lt)/ }.each do |key|
132
132
  expect(html).not_to match /<option value="#{key}">/
133
133
  end
134
134
  end
135
135
  it 'excludes compounds when compounds: false' do
136
- html = @f.predicate_select :compounds => false
136
+ html = @f.predicate_select compounds: false
137
137
  Predicate.names.select { |k| k =~ /_(any|all)$/ }.each do |key|
138
138
  expect(html).not_to match /<option value="#{key}">/
139
139
  end