ransack 2.3.0 → 2.4.2
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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/cronjob.yml +105 -0
- data/.github/workflows/rubocop.yml +20 -0
- data/.github/workflows/test.yml +154 -0
- data/.rubocop.yml +44 -0
- data/CHANGELOG.md +31 -1
- data/CONTRIBUTING.md +13 -11
- data/Gemfile +19 -5
- data/README.md +119 -54
- data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +78 -0
- data/bug_report_templates/test-ransacker-arel-present-predicate.rb +71 -0
- data/docs/img/create_release.png +0 -0
- data/docs/release_process.md +20 -0
- data/{polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2 → lib/polyamorous/activerecord_5.2_ruby_2}/join_association.rb +4 -2
- data/{polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2 → lib/polyamorous/activerecord_5.2_ruby_2}/join_dependency.rb +0 -2
- data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
- data/{polyamorous/lib → lib}/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +0 -1
- data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
- data/{polyamorous/lib → lib}/polyamorous/activerecord_6.1_ruby_2/reflection.rb +0 -1
- data/lib/polyamorous/activerecord_6.2_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_6.2_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_6.2_ruby_2/reflection.rb +1 -0
- data/{polyamorous/lib → lib}/polyamorous/join.rb +0 -0
- data/{polyamorous/lib → lib/polyamorous}/polyamorous.rb +3 -8
- data/{polyamorous/lib → lib}/polyamorous/swapping_reflection_class.rb +0 -0
- data/{polyamorous/lib → lib}/polyamorous/tree_node.rb +0 -0
- data/lib/ransack.rb +3 -4
- data/lib/ransack/adapters/active_record/base.rb +4 -0
- data/lib/ransack/adapters/active_record/context.rb +51 -80
- data/lib/ransack/adapters/active_record/ransack/constants.rb +13 -1
- data/lib/ransack/adapters/active_record/ransack/context.rb +2 -6
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +11 -4
- data/lib/ransack/configuration.rb +17 -1
- data/lib/ransack/constants.rb +2 -5
- data/lib/ransack/helpers.rb +1 -1
- data/lib/ransack/helpers/form_builder.rb +8 -14
- data/lib/ransack/locale/sk.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +1 -1
- data/lib/ransack/nodes/condition.rb +7 -1
- data/lib/ransack/nodes/grouping.rb +1 -1
- data/lib/ransack/nodes/sort.rb +1 -1
- data/lib/ransack/nodes/value.rb +1 -1
- data/lib/ransack/predicate.rb +2 -1
- data/lib/ransack/search.rb +3 -1
- data/lib/ransack/translate.rb +3 -3
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +8 -23
- data/spec/blueprints/articles.rb +1 -1
- data/spec/blueprints/comments.rb +1 -1
- data/spec/blueprints/notes.rb +1 -1
- data/spec/blueprints/tags.rb +1 -1
- data/spec/console.rb +5 -5
- data/spec/helpers/polyamorous_helper.rb +1 -10
- data/spec/helpers/ransack_helper.rb +1 -1
- data/spec/{ransack → polyamorous}/join_association_spec.rb +7 -0
- data/spec/{ransack → polyamorous}/join_dependency_spec.rb +0 -0
- data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +9 -6
- data/spec/ransack/adapters/active_record/context_spec.rb +19 -18
- data/spec/ransack/configuration_spec.rb +10 -0
- data/spec/ransack/helpers/form_helper_spec.rb +16 -16
- data/spec/ransack/nodes/grouping_spec.rb +2 -2
- data/spec/ransack/predicate_spec.rb +39 -1
- data/spec/ransack/search_spec.rb +105 -17
- data/spec/spec_helper.rb +9 -5
- data/spec/support/schema.rb +8 -3
- metadata +41 -177
- data/.travis.yml +0 -49
- data/polyamorous/lib/polyamorous/activerecord_5.0_ruby_2/join_association.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +0 -31
- data/polyamorous/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +0 -112
- data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +0 -31
- data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +0 -112
- data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/reflection.rb +0 -12
- data/polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2/reflection.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +0 -2
- data/polyamorous/lib/polyamorous/version.rb +0 -3
- data/polyamorous/polyamorous.gemspec +0 -35
data/spec/blueprints/tags.rb
CHANGED
data/spec/console.rb
CHANGED
|
@@ -14,11 +14,11 @@ Sham.define do
|
|
|
14
14
|
title { Faker::Lorem.sentence }
|
|
15
15
|
body { Faker::Lorem.paragraph }
|
|
16
16
|
salary { |index| 30000 + (index * 1000) }
|
|
17
|
-
tag_name { Faker::Lorem.words(3).join(' ') }
|
|
18
|
-
note { Faker::Lorem.words(7).join(' ') }
|
|
19
|
-
only_admin { Faker::Lorem.words(3).join(' ') }
|
|
20
|
-
only_search { Faker::Lorem.words(3).join(' ') }
|
|
21
|
-
only_sort { Faker::Lorem.words(3).join(' ') }
|
|
17
|
+
tag_name { Faker::Lorem.words(number: 3).join(' ') }
|
|
18
|
+
note { Faker::Lorem.words(number: 7).join(' ') }
|
|
19
|
+
only_admin { Faker::Lorem.words(number: 3).join(' ') }
|
|
20
|
+
only_search { Faker::Lorem.words(number: 3).join(' ') }
|
|
21
|
+
only_sort { Faker::Lorem.words(number: 3).join(' ') }
|
|
22
22
|
notable_id { |id| id }
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -7,18 +7,9 @@ module PolyamorousHelper
|
|
|
7
7
|
def new_join_dependency(klass, associations = {})
|
|
8
8
|
Polyamorous::JoinDependency.new klass, klass.arel_table, associations, Polyamorous::InnerJoin
|
|
9
9
|
end
|
|
10
|
-
elsif ActiveRecord.version > ::Gem::Version.new("5.2.0")
|
|
11
|
-
def new_join_dependency(klass, associations = {})
|
|
12
|
-
Polyamorous::JoinDependency.new klass, klass.arel_table, associations
|
|
13
|
-
end
|
|
14
|
-
elsif ActiveRecord.version == ::Gem::Version.new("5.2.0")
|
|
15
|
-
def new_join_dependency(klass, associations = {})
|
|
16
|
-
alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(klass.connection, klass.table_name, [])
|
|
17
|
-
Polyamorous::JoinDependency.new klass, klass.arel_table, associations, alias_tracker
|
|
18
|
-
end
|
|
19
10
|
else
|
|
20
11
|
def new_join_dependency(klass, associations = {})
|
|
21
|
-
Polyamorous::JoinDependency.new klass,
|
|
12
|
+
Polyamorous::JoinDependency.new klass, klass.arel_table, associations
|
|
22
13
|
end
|
|
23
14
|
end
|
|
24
15
|
|
|
@@ -10,6 +10,13 @@ module Polyamorous
|
|
|
10
10
|
new_join_association(reflection, parent.children, Article)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
subject { new_join_association(reflection, parent.children, Person) }
|
|
14
|
+
|
|
15
|
+
it 'respects polymorphism on equality test' do
|
|
16
|
+
expect(subject).to eq new_join_association(reflection, parent.children, Person)
|
|
17
|
+
expect(subject).not_to eq new_join_association(reflection, parent.children, Article)
|
|
18
|
+
end
|
|
19
|
+
|
|
13
20
|
it 'leaves the orginal reflection intact for thread safety' do
|
|
14
21
|
reflection.instance_variable_set(:@klass, Article)
|
|
15
22
|
join_association
|
|
File without changes
|
|
File without changes
|
|
@@ -122,6 +122,10 @@ module Ransack
|
|
|
122
122
|
expect { Person.ransack('') }.to_not raise_error
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
+
it 'raises exception if ransack! called with unknown condition' do
|
|
126
|
+
expect { Person.ransack!(unknown_attr_eq: 'Ernie') }.to raise_error
|
|
127
|
+
end
|
|
128
|
+
|
|
125
129
|
it 'does not modify the parameters' do
|
|
126
130
|
params = { name_eq: '' }
|
|
127
131
|
expect { Person.ransack(params) }.not_to change { params }
|
|
@@ -143,14 +147,12 @@ module Ransack
|
|
|
143
147
|
it 'removes redundant joins from top query' do
|
|
144
148
|
s = Article.ransack(tags_name_not_eq: "Fantasy")
|
|
145
149
|
sql = s.result.to_sql
|
|
146
|
-
|
|
147
150
|
expect(sql).to_not include('LEFT OUTER JOIN')
|
|
148
151
|
end
|
|
149
152
|
|
|
150
153
|
it 'handles != for single values' do
|
|
151
154
|
s = Article.ransack(tags_name_not_eq: "Fantasy")
|
|
152
155
|
articles = s.result.to_a
|
|
153
|
-
|
|
154
156
|
expect(articles).to include marco
|
|
155
157
|
expect(articles).to_not include arthur
|
|
156
158
|
end
|
|
@@ -267,10 +269,12 @@ module Ransack
|
|
|
267
269
|
# end
|
|
268
270
|
|
|
269
271
|
it 'creates ransack attributes' do
|
|
272
|
+
person = Person.create!(name: 'Aric Smith')
|
|
273
|
+
|
|
270
274
|
s = Person.ransack(reversed_name_eq: 'htimS cirA')
|
|
271
275
|
expect(s.result.size).to eq(1)
|
|
272
276
|
|
|
273
|
-
expect(s.result.first).to eq
|
|
277
|
+
expect(s.result.first).to eq person
|
|
274
278
|
end
|
|
275
279
|
|
|
276
280
|
it 'can be accessed through associations' do
|
|
@@ -460,9 +464,9 @@ module Ransack
|
|
|
460
464
|
Comment.create(article: Article.create(title: 'Avenger'), person: Person.create(salary: 100_000)),
|
|
461
465
|
Comment.create(article: Article.create(title: 'Avenge'), person: Person.create(salary: 50_000)),
|
|
462
466
|
]
|
|
463
|
-
expect(Comment.ransack(article_title_cont: 'aven',s: 'person_salary desc').result).to eq(comments)
|
|
467
|
+
expect(Comment.ransack(article_title_cont: 'aven', s: 'person_salary desc').result).to eq(comments)
|
|
464
468
|
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)
|
|
469
|
+
expect(Comment.joins(:person).ransack(article_title_cont: 'aven', s: 'persons_salary desc').result).to eq(comments)
|
|
466
470
|
end
|
|
467
471
|
|
|
468
472
|
it 'allows sort by `only_sort` field' do
|
|
@@ -541,7 +545,6 @@ module Ransack
|
|
|
541
545
|
)
|
|
542
546
|
end
|
|
543
547
|
|
|
544
|
-
|
|
545
548
|
it 'should allow passing ransacker arguments to a ransacker' do
|
|
546
549
|
s = Person.ransack(
|
|
547
550
|
c: [{
|
|
@@ -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
|
|
@@ -173,5 +173,15 @@ module Ransack
|
|
|
173
173
|
.to eq false
|
|
174
174
|
end
|
|
175
175
|
end
|
|
176
|
+
|
|
177
|
+
it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
|
|
178
|
+
default = Ransack.options.clone
|
|
179
|
+
|
|
180
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
|
|
181
|
+
|
|
182
|
+
expect(Ransack.options[:postgres_fields_sort_option]).to eq :nulls_first
|
|
183
|
+
|
|
184
|
+
Ransack.options = default
|
|
185
|
+
end
|
|
176
186
|
end
|
|
177
187
|
end
|
|
@@ -186,7 +186,7 @@ module Ransack
|
|
|
186
186
|
)
|
|
187
187
|
}
|
|
188
188
|
it {
|
|
189
|
-
should match(
|
|
189
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
190
190
|
)
|
|
191
191
|
}
|
|
192
192
|
it { should match /sort_link desc/ }
|
|
@@ -202,7 +202,7 @@ module Ransack
|
|
|
202
202
|
)
|
|
203
203
|
}
|
|
204
204
|
it {
|
|
205
|
-
should match(
|
|
205
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
206
206
|
)
|
|
207
207
|
}
|
|
208
208
|
end
|
|
@@ -216,7 +216,7 @@ module Ransack
|
|
|
216
216
|
)
|
|
217
217
|
}
|
|
218
218
|
it {
|
|
219
|
-
should match(
|
|
219
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
220
220
|
)
|
|
221
221
|
}
|
|
222
222
|
it { should match /sort_link desc/ }
|
|
@@ -232,7 +232,7 @@ module Ransack
|
|
|
232
232
|
)
|
|
233
233
|
}
|
|
234
234
|
it {
|
|
235
|
-
should match(
|
|
235
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
236
236
|
)
|
|
237
237
|
}
|
|
238
238
|
end
|
|
@@ -258,7 +258,7 @@ module Ransack
|
|
|
258
258
|
)
|
|
259
259
|
}
|
|
260
260
|
it {
|
|
261
|
-
should match(
|
|
261
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
262
262
|
)
|
|
263
263
|
}
|
|
264
264
|
it { should match /sort_link desc/ }
|
|
@@ -274,7 +274,7 @@ module Ransack
|
|
|
274
274
|
)
|
|
275
275
|
}
|
|
276
276
|
it {
|
|
277
|
-
should match(
|
|
277
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
278
278
|
)
|
|
279
279
|
}
|
|
280
280
|
end
|
|
@@ -289,7 +289,7 @@ module Ransack
|
|
|
289
289
|
)
|
|
290
290
|
}
|
|
291
291
|
it {
|
|
292
|
-
should match(
|
|
292
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
293
293
|
)
|
|
294
294
|
}
|
|
295
295
|
it { should match /sort_link/ }
|
|
@@ -306,7 +306,7 @@ module Ransack
|
|
|
306
306
|
)
|
|
307
307
|
}
|
|
308
308
|
it {
|
|
309
|
-
should match(
|
|
309
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
310
310
|
)
|
|
311
311
|
}
|
|
312
312
|
end
|
|
@@ -321,7 +321,7 @@ module Ransack
|
|
|
321
321
|
)
|
|
322
322
|
}
|
|
323
323
|
it {
|
|
324
|
-
should match(
|
|
324
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
325
325
|
)
|
|
326
326
|
}
|
|
327
327
|
it { should match /sort_link/ }
|
|
@@ -338,7 +338,7 @@ module Ransack
|
|
|
338
338
|
)
|
|
339
339
|
}
|
|
340
340
|
it {
|
|
341
|
-
should match(
|
|
341
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
342
342
|
)
|
|
343
343
|
}
|
|
344
344
|
end
|
|
@@ -353,7 +353,7 @@ module Ransack
|
|
|
353
353
|
)
|
|
354
354
|
}
|
|
355
355
|
it {
|
|
356
|
-
should match(
|
|
356
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+asc/
|
|
357
357
|
)
|
|
358
358
|
}
|
|
359
359
|
it { should match /sort_link/ }
|
|
@@ -370,7 +370,7 @@ module Ransack
|
|
|
370
370
|
)
|
|
371
371
|
}
|
|
372
372
|
it {
|
|
373
|
-
should match(
|
|
373
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+asc/
|
|
374
374
|
)
|
|
375
375
|
}
|
|
376
376
|
end
|
|
@@ -385,7 +385,7 @@ module Ransack
|
|
|
385
385
|
)
|
|
386
386
|
}
|
|
387
387
|
it {
|
|
388
|
-
should match(
|
|
388
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
389
389
|
)
|
|
390
390
|
}
|
|
391
391
|
it { should match /sort_link/ }
|
|
@@ -402,7 +402,7 @@ module Ransack
|
|
|
402
402
|
)
|
|
403
403
|
}
|
|
404
404
|
it {
|
|
405
|
-
should match(
|
|
405
|
+
should match(/people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/
|
|
406
406
|
)
|
|
407
407
|
}
|
|
408
408
|
end
|
|
@@ -643,13 +643,13 @@ module Ransack
|
|
|
643
643
|
before do
|
|
644
644
|
Ransack.configure do |c|
|
|
645
645
|
c.hide_sort_order_indicators = false
|
|
646
|
-
c.custom_arrows = { default_arrow: "defaultarrow"}
|
|
646
|
+
c.custom_arrows = { default_arrow: "defaultarrow" }
|
|
647
647
|
end
|
|
648
648
|
end
|
|
649
649
|
|
|
650
650
|
after do
|
|
651
651
|
Ransack.configure do |c|
|
|
652
|
-
c.custom_arrows = { default_arrow: nil}
|
|
652
|
+
c.custom_arrows = { default_arrow: nil }
|
|
653
653
|
end
|
|
654
654
|
end
|
|
655
655
|
|
|
@@ -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',
|
|
@@ -159,6 +159,44 @@ module Ransack
|
|
|
159
159
|
end
|
|
160
160
|
end
|
|
161
161
|
|
|
162
|
+
describe 'i_cont' do
|
|
163
|
+
it_has_behavior 'wildcard escaping', :name_i_cont,
|
|
164
|
+
(if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
|
165
|
+
/"people"."name" ILIKE '%\\%\\.\\_\\\\%'/
|
|
166
|
+
elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
|
|
167
|
+
/LOWER\(`people`.`name`\) LIKE '%\\\\%.\\\\_\\\\\\\\%'/
|
|
168
|
+
else
|
|
169
|
+
/LOWER\("people"."name"\) LIKE '%%._\\%'/
|
|
170
|
+
end) do
|
|
171
|
+
subject { @s }
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'generates a LIKE query with LOWER(column) and value surrounded by %' do
|
|
175
|
+
@s.name_i_cont = 'Ric'
|
|
176
|
+
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
|
177
|
+
expect(@s.result.to_sql).to match /[LOWER\(]?#{field}\)? I?LIKE '%ric%'/
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
describe 'not_i_cont' do
|
|
182
|
+
it_has_behavior 'wildcard escaping', :name_not_i_cont,
|
|
183
|
+
(if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
|
184
|
+
/"people"."name" NOT ILIKE '%\\%\\.\\_\\\\%'/
|
|
185
|
+
elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
|
|
186
|
+
/LOWER\(`people`.`name`\) NOT LIKE '%\\\\%.\\\\_\\\\\\\\%'/
|
|
187
|
+
else
|
|
188
|
+
/LOWER\("people"."name"\) NOT LIKE '%%._\\%'/
|
|
189
|
+
end) do
|
|
190
|
+
subject { @s }
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it 'generates a NOT LIKE query with LOWER(column) and value surrounded by %' do
|
|
194
|
+
@s.name_not_i_cont = 'Ric'
|
|
195
|
+
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
|
196
|
+
expect(@s.result.to_sql).to match /[LOWER\(]?#{field}\)? NOT I?LIKE '%ric%'/
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
162
200
|
describe 'start' do
|
|
163
201
|
it 'generates a LIKE query with value followed by %' do
|
|
164
202
|
@s.name_start = 'Er'
|
|
@@ -384,7 +422,7 @@ module Ransack
|
|
|
384
422
|
context "defining custom predicates" do
|
|
385
423
|
describe "with 'not_in' arel predicate" do
|
|
386
424
|
before do
|
|
387
|
-
Ransack.configure {|c| c.add_predicate "not_in_csv", arel_predicate: "not_in", formatter: proc { |v| v.split(",") } }
|
|
425
|
+
Ransack.configure { |c| c.add_predicate "not_in_csv", arel_predicate: "not_in", formatter: proc { |v| v.split(",") } }
|
|
388
426
|
end
|
|
389
427
|
|
|
390
428
|
it 'generates a value IS NOT NULL query' do
|
data/spec/ransack/search_spec.rb
CHANGED
|
@@ -20,6 +20,12 @@ module Ransack
|
|
|
20
20
|
Search.new(Person, name_eq: 'foobar')
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
it 'strip leading & trailing whitespace before building' do
|
|
24
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
25
|
+
.with({ 'name_eq' => 'foobar' })
|
|
26
|
+
Search.new(Person, name_eq: ' foobar ')
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
it 'removes empty suffixed conditions before building' do
|
|
24
30
|
expect_any_instance_of(Search).to receive(:build).with({})
|
|
25
31
|
Search.new(Person, name_eq_any: [''])
|
|
@@ -109,6 +115,43 @@ module Ransack
|
|
|
109
115
|
expect(s.result.to_sql).to include 'published'
|
|
110
116
|
end
|
|
111
117
|
|
|
118
|
+
# The failure/oversight in Ransack::Nodes::Condition#arel_predicate or deeper is beyond my understanding of the structures
|
|
119
|
+
it 'preserves (inverts) default scope and conditions for negative subqueries' do
|
|
120
|
+
# the positive case (published_articles_title_eq) is
|
|
121
|
+
# SELECT "people".* FROM "people"
|
|
122
|
+
# LEFT OUTER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
|
123
|
+
# AND "articles"."published" = 't'
|
|
124
|
+
# AND ('default_scope' = 'default_scope')
|
|
125
|
+
# WHERE "articles"."title" = 'Test' ORDER BY "people"."id" DESC
|
|
126
|
+
#
|
|
127
|
+
# negative case was
|
|
128
|
+
# SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
|
|
129
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
130
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
131
|
+
# AND NOT ("articles"."title" != 'Test')
|
|
132
|
+
# ) ORDER BY "people"."id" DESC
|
|
133
|
+
#
|
|
134
|
+
# Should have been like
|
|
135
|
+
# SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
|
|
136
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
137
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
138
|
+
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
|
139
|
+
# ) ORDER BY "people"."id" DESC
|
|
140
|
+
#
|
|
141
|
+
# With tenanting (eg default_scope with column reference), NOT IN should be like
|
|
142
|
+
# SELECT "people".* FROM "people" WHERE "people"."tenant_id" = 'tenant_id' AND "people"."id" NOT IN (
|
|
143
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
144
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
145
|
+
# AND "articles"."tenant_id" = 'tenant_id'
|
|
146
|
+
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
|
147
|
+
# ) ORDER BY "people"."id" DESC
|
|
148
|
+
|
|
149
|
+
pending("spec should pass, but I do not know how/where to fix lib code")
|
|
150
|
+
s = Search.new(Person, published_articles_title_not_eq: 'Test')
|
|
151
|
+
expect(s.result.to_sql).to include 'default_scope'
|
|
152
|
+
expect(s.result.to_sql).to include 'published'
|
|
153
|
+
end
|
|
154
|
+
|
|
112
155
|
it 'discards empty conditions' do
|
|
113
156
|
s = Search.new(Person, children_name_eq: '')
|
|
114
157
|
condition = s.base[:children_name_eq]
|
|
@@ -189,7 +232,7 @@ module Ransack
|
|
|
189
232
|
context 'with an invalid condition' do
|
|
190
233
|
subject { Search.new(Person, unknown_attr_eq: 'Ernie') }
|
|
191
234
|
|
|
192
|
-
context 'when ignore_unknown_conditions is false' do
|
|
235
|
+
context 'when ignore_unknown_conditions configuration option is false' do
|
|
193
236
|
before do
|
|
194
237
|
Ransack.configure { |c| c.ignore_unknown_conditions = false }
|
|
195
238
|
end
|
|
@@ -197,13 +240,39 @@ module Ransack
|
|
|
197
240
|
specify { expect { subject }.to raise_error ArgumentError }
|
|
198
241
|
end
|
|
199
242
|
|
|
200
|
-
context 'when ignore_unknown_conditions is true' do
|
|
243
|
+
context 'when ignore_unknown_conditions configuration option is true' do
|
|
201
244
|
before do
|
|
202
245
|
Ransack.configure { |c| c.ignore_unknown_conditions = true }
|
|
203
246
|
end
|
|
204
247
|
|
|
205
248
|
specify { expect { subject }.not_to raise_error }
|
|
206
249
|
end
|
|
250
|
+
|
|
251
|
+
subject(:with_ignore_unknown_conditions_false) {
|
|
252
|
+
Search.new(Person,
|
|
253
|
+
{ unknown_attr_eq: 'Ernie' },
|
|
254
|
+
{ ignore_unknown_conditions: false }
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
subject(:with_ignore_unknown_conditions_true) {
|
|
259
|
+
Search.new(Person,
|
|
260
|
+
{ unknown_attr_eq: 'Ernie' },
|
|
261
|
+
{ ignore_unknown_conditions: true }
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
context 'when ignore_unknown_conditions search parameter is absent' do
|
|
266
|
+
specify { expect { subject }.not_to raise_error }
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
context 'when ignore_unknown_conditions search parameter is false' do
|
|
270
|
+
specify { expect { with_ignore_unknown_conditions_false }.to raise_error ArgumentError }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
context 'when ignore_unknown_conditions search parameter is true' do
|
|
274
|
+
specify { expect { with_ignore_unknown_conditions_true }.not_to raise_error }
|
|
275
|
+
end
|
|
207
276
|
end
|
|
208
277
|
|
|
209
278
|
it 'does not modify the parameters' do
|
|
@@ -220,6 +289,9 @@ module Ransack
|
|
|
220
289
|
let(:children_people_name_field) {
|
|
221
290
|
"#{quote_table_name("children_people")}.#{quote_column_name("name")}"
|
|
222
291
|
}
|
|
292
|
+
let(:notable_type_field) {
|
|
293
|
+
"#{quote_table_name("notes")}.#{quote_column_name("notable_type")}"
|
|
294
|
+
}
|
|
223
295
|
it 'evaluates conditions contextually' do
|
|
224
296
|
s = Search.new(Person, children_name_eq: 'Ernie')
|
|
225
297
|
expect(s.result).to be_an ActiveRecord::Relation
|
|
@@ -228,19 +300,22 @@ module Ransack
|
|
|
228
300
|
end
|
|
229
301
|
|
|
230
302
|
it 'use appropriate table alias' do
|
|
231
|
-
skip "
|
|
303
|
+
skip "Rails 6 regressed here, but it's fixed in 6-0-stable since https://github.com/rails/rails/commit/f9ba52477ca288e7effa5f6794ae3df3f4e982bc" if ENV["RAILS"] == "v6.0.3"
|
|
304
|
+
|
|
232
305
|
s = Search.new(Person, {
|
|
233
306
|
name_eq: "person_name_query",
|
|
234
307
|
articles_title_eq: "person_article_title_query",
|
|
235
308
|
parent_name_eq: "parent_name_query",
|
|
236
309
|
parent_articles_title_eq: 'parents_article_title_query'
|
|
237
310
|
}).result
|
|
311
|
+
|
|
238
312
|
real_query = remove_quotes_and_backticks(s.to_sql)
|
|
239
313
|
|
|
240
314
|
expect(real_query)
|
|
241
|
-
|
|
315
|
+
.to match(%r{LEFT OUTER JOIN articles ON (\('default_scope' = 'default_scope'\) AND )?articles.person_id = people.id})
|
|
242
316
|
expect(real_query)
|
|
243
|
-
|
|
317
|
+
.to match(%r{LEFT OUTER JOIN articles articles_people ON (\('default_scope' = 'default_scope'\) AND )?articles_people.person_id = parents_people.id})
|
|
318
|
+
|
|
244
319
|
expect(real_query)
|
|
245
320
|
.to include "people.name = 'person_name_query'"
|
|
246
321
|
expect(real_query)
|
|
@@ -251,13 +326,7 @@ module Ransack
|
|
|
251
326
|
.to include "articles_people.title = 'parents_article_title_query'"
|
|
252
327
|
end
|
|
253
328
|
|
|
254
|
-
|
|
255
|
-
# commenting out lines 221 and 242 to run the test. Addresses issue #374.
|
|
256
|
-
# https://github.com/activerecord-hackery/ransack/issues/374
|
|
257
|
-
#
|
|
258
|
-
it 'evaluates conditions for multiple `belongs_to` associations to the
|
|
259
|
-
same table contextually' do
|
|
260
|
-
skip "Make this spec pass for Rails <5.2" if ::ActiveRecord::VERSION::STRING < '5.2.0'
|
|
329
|
+
it 'evaluates conditions for multiple `belongs_to` associations to the same table contextually' do
|
|
261
330
|
s = Search.new(
|
|
262
331
|
Recommendation,
|
|
263
332
|
person_name_eq: 'Ernie',
|
|
@@ -289,6 +358,7 @@ module Ransack
|
|
|
289
358
|
s = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie').result
|
|
290
359
|
expect(s).to be_an ActiveRecord::Relation
|
|
291
360
|
expect(s.to_sql).to match /#{people_name_field} = 'Ernie'/
|
|
361
|
+
expect(s.to_sql).to match /#{notable_type_field} = 'Person'/
|
|
292
362
|
end
|
|
293
363
|
|
|
294
364
|
it 'evaluates nested conditions' do
|
|
@@ -327,11 +397,8 @@ module Ransack
|
|
|
327
397
|
{ m: 'or', comments_body_cont: 'e', articles_comments_body_cont: 'e' }
|
|
328
398
|
]
|
|
329
399
|
)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
else
|
|
333
|
-
all_or_load, uniq_or_distinct = :load, :distinct
|
|
334
|
-
end
|
|
400
|
+
|
|
401
|
+
all_or_load, uniq_or_distinct = :load, :distinct
|
|
335
402
|
expect(s.result.send(all_or_load).size)
|
|
336
403
|
.to eq(9000)
|
|
337
404
|
expect(s.result(distinct: true).size)
|
|
@@ -466,6 +533,27 @@ module Ransack
|
|
|
466
533
|
@s.sorts = 'id asc'
|
|
467
534
|
expect(@s.result.first.id).to eq 1
|
|
468
535
|
end
|
|
536
|
+
|
|
537
|
+
it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
|
|
538
|
+
default = Ransack.options.clone
|
|
539
|
+
|
|
540
|
+
s = Search.new(Person, s: 'name asc')
|
|
541
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC"
|
|
542
|
+
|
|
543
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
|
|
544
|
+
s = Search.new(Person, s: 'name asc')
|
|
545
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS FIRST"
|
|
546
|
+
s = Search.new(Person, s: 'name desc')
|
|
547
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS LAST"
|
|
548
|
+
|
|
549
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_last }
|
|
550
|
+
s = Search.new(Person, s: 'name asc')
|
|
551
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS LAST"
|
|
552
|
+
s = Search.new(Person, s: 'name desc')
|
|
553
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS FIRST"
|
|
554
|
+
|
|
555
|
+
Ransack.options = default
|
|
556
|
+
end
|
|
469
557
|
end
|
|
470
558
|
|
|
471
559
|
describe '#method_missing' do
|