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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/codeql.yml +72 -0
- data/.github/workflows/cronjob.yml +99 -0
- data/.github/workflows/deploy.yml +35 -0
- data/.github/workflows/rubocop.yml +20 -0
- data/.github/workflows/test-deploy.yml +29 -0
- data/.github/workflows/test.yml +131 -0
- data/.nojekyll +0 -0
- data/.rubocop.yml +50 -0
- data/CHANGELOG.md +263 -1
- data/CONTRIBUTING.md +51 -29
- data/Gemfile +24 -10
- data/README.md +49 -917
- data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +78 -0
- data/bug_report_templates/test-ransacker-arel-present-predicate.rb +75 -0
- data/docs/.gitignore +19 -0
- data/docs/.nojekyll +0 -0
- data/docs/babel.config.js +3 -0
- data/docs/blog/2022-03-27-ransack-3.0.0.md +20 -0
- data/docs/docs/getting-started/_category_.json +4 -0
- data/docs/docs/getting-started/advanced-mode.md +46 -0
- data/docs/docs/getting-started/configuration.md +47 -0
- data/docs/docs/getting-started/search-matches.md +67 -0
- data/docs/docs/getting-started/simple-mode.md +288 -0
- data/docs/docs/getting-started/sorting.md +71 -0
- data/docs/docs/getting-started/using-predicates.md +282 -0
- data/docs/docs/going-further/_category_.json +4 -0
- data/docs/docs/going-further/acts-as-taggable-on.md +114 -0
- data/docs/docs/going-further/associations.md +70 -0
- data/docs/docs/going-further/custom-predicates.md +52 -0
- data/docs/docs/going-further/documentation.md +43 -0
- data/docs/docs/going-further/exporting-to-csv.md +49 -0
- data/docs/docs/going-further/external-guides.md +57 -0
- data/docs/docs/going-further/form-customisation.md +63 -0
- data/docs/docs/going-further/i18n.md +53 -0
- data/docs/docs/going-further/img/create_release.png +0 -0
- data/docs/docs/going-further/merging-searches.md +41 -0
- data/docs/docs/going-further/other-notes.md +428 -0
- data/docs/docs/going-further/polymorphic-search.md +46 -0
- data/docs/docs/going-further/ransackers.md +331 -0
- data/docs/docs/going-further/release_process.md +36 -0
- data/docs/docs/going-further/saving-queries.md +82 -0
- data/docs/docs/going-further/searching-postgres.md +57 -0
- data/docs/docs/going-further/wiki-contributors.md +82 -0
- data/docs/docs/intro.md +99 -0
- data/docs/docusaurus.config.js +120 -0
- data/docs/package.json +42 -0
- data/docs/sidebars.js +31 -0
- data/docs/src/components/HomepageFeatures/index.js +64 -0
- data/docs/src/components/HomepageFeatures/styles.module.css +11 -0
- data/docs/src/css/custom.css +39 -0
- data/docs/src/pages/index.module.css +23 -0
- data/docs/src/pages/markdown-page.md +7 -0
- data/docs/static/.nojekyll +0 -0
- data/docs/static/img/docusaurus.png +0 -0
- data/docs/static/img/favicon.ico +0 -0
- data/docs/static/img/logo.svg +1 -0
- data/docs/static/img/tutorial/docsVersionDropdown.png +0 -0
- data/docs/static/img/tutorial/localeDropdown.png +0 -0
- data/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
- data/docs/static/img/undraw_docusaurus_react.svg +170 -0
- data/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- data/docs/yarn.lock +8879 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +70 -0
- data/{polyamorous/lib/polyamorous/activerecord_6.0_ruby_2 → lib/polyamorous/activerecord_6.1_ruby_2}/join_dependency.rb +33 -12
- data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +11 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_7.1_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_7.1_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_7.1_ruby_2/reflection.rb +1 -0
- data/{polyamorous/lib → lib/polyamorous}/polyamorous.rb +3 -8
- data/lib/ransack/adapters/active_record/base.rb +83 -10
- data/lib/ransack/adapters/active_record/context.rb +61 -116
- data/lib/ransack/configuration.rb +53 -10
- data/lib/ransack/constants.rb +126 -7
- data/lib/ransack/context.rb +34 -5
- data/lib/ransack/helpers/form_builder.rb +11 -17
- data/lib/ransack/helpers/form_helper.rb +14 -5
- data/lib/ransack/helpers.rb +1 -1
- data/lib/ransack/locale/sk.yml +70 -0
- data/lib/ransack/locale/sv.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +3 -3
- data/lib/ransack/nodes/condition.rb +87 -8
- data/lib/ransack/nodes/grouping.rb +4 -4
- data/lib/ransack/nodes/node.rb +1 -1
- data/lib/ransack/nodes/sort.rb +3 -3
- data/lib/ransack/nodes/value.rb +3 -3
- data/lib/ransack/predicate.rb +3 -2
- data/lib/ransack/ransacker.rb +1 -1
- data/lib/ransack/search.rb +15 -7
- data/lib/ransack/translate.rb +6 -6
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +38 -2
- data/lib/ransack.rb +6 -10
- data/ransack.gemspec +9 -24
- 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 +2 -17
- data/spec/helpers/ransack_helper.rb +1 -1
- data/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
- data/spec/{ransack → polyamorous}/join_association_spec.rb +3 -1
- data/spec/{ransack → polyamorous}/join_dependency_spec.rb +0 -16
- data/spec/ransack/adapters/active_record/base_spec.rb +125 -16
- data/spec/ransack/adapters/active_record/context_spec.rb +19 -18
- data/spec/ransack/configuration_spec.rb +33 -9
- data/spec/ransack/helpers/form_builder_spec.rb +8 -8
- data/spec/ransack/helpers/form_helper_spec.rb +109 -20
- data/spec/ransack/nodes/condition_spec.rb +37 -0
- data/spec/ransack/nodes/grouping_spec.rb +2 -2
- data/spec/ransack/nodes/value_spec.rb +115 -0
- data/spec/ransack/predicate_spec.rb +75 -2
- data/spec/ransack/search_spec.rb +239 -38
- data/spec/ransack/translate_spec.rb +1 -1
- data/spec/spec_helper.rb +9 -5
- data/spec/support/schema.rb +111 -12
- metadata +105 -195
- data/.travis.yml +0 -49
- data/lib/ransack/adapters/active_record/ransack/constants.rb +0 -116
- data/lib/ransack/adapters/active_record/ransack/context.rb +0 -60
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +0 -61
- data/lib/ransack/adapters/active_record/ransack/translate.rb +0 -8
- data/lib/ransack/adapters/active_record/ransack/visitor.rb +0 -47
- data/lib/ransack/adapters.rb +0 -64
- data/lib/ransack/nodes.rb +0 -8
- 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/join_association.rb +0 -22
- data/polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2/join_dependency.rb +0 -81
- 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/activerecord_6.1_ruby_2/reflection.rb +0 -2
- data/polyamorous/lib/polyamorous/version.rb +0 -3
- data/polyamorous/polyamorous.gemspec +0 -35
- /data/{logo → docs/static/logo}/ransack-h.png +0 -0
- /data/{logo → docs/static/logo}/ransack-h.svg +0 -0
- /data/{logo → docs/static/logo}/ransack-v.png +0 -0
- /data/{logo → docs/static/logo}/ransack-v.svg +0 -0
- /data/{logo → docs/static/logo}/ransack.png +0 -0
- /data/{logo → docs/static/logo}/ransack.svg +0 -0
- /data/{polyamorous/lib → lib}/polyamorous/join.rb +0 -0
- /data/{polyamorous/lib → lib}/polyamorous/swapping_reflection_class.rb +0 -0
- /data/{polyamorous/lib → lib}/polyamorous/tree_node.rb +0 -0
- /data/lib/ransack/{adapters/active_record.rb → active_record.rb} +0 -0
- /data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
data/spec/ransack/search_spec.rb
CHANGED
|
@@ -20,6 +20,44 @@ module Ransack
|
|
|
20
20
|
Search.new(Person, name_eq: 'foobar')
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
context 'whitespace stripping' do
|
|
24
|
+
context 'when whitespace_strip option is true' do
|
|
25
|
+
before do
|
|
26
|
+
Ransack.configure { |c| c.strip_whitespace = true }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'strips leading & trailing whitespace before building' do
|
|
30
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
31
|
+
.with({ 'name_eq' => 'foobar' })
|
|
32
|
+
Search.new(Person, name_eq: ' foobar ')
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'when whitespace_strip option is false' do
|
|
37
|
+
before do
|
|
38
|
+
Ransack.configure { |c| c.strip_whitespace = false }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'doesn\'t strip leading & trailing whitespace before building' do
|
|
42
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
43
|
+
.with({ 'name_eq' => ' foobar ' })
|
|
44
|
+
Search.new(Person, name_eq: ' foobar ')
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'strips leading & trailing whitespace when strip_whitespace search parameter is true' do
|
|
49
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
50
|
+
.with({ 'name_eq' => 'foobar' })
|
|
51
|
+
Search.new(Person, { name_eq: ' foobar ' }, { strip_whitespace: true })
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'doesn\'t strip leading & trailing whitespace when strip_whitespace search parameter is false' do
|
|
55
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
56
|
+
.with({ 'name_eq' => ' foobar ' })
|
|
57
|
+
Search.new(Person, { name_eq: ' foobar ' }, { strip_whitespace: false })
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
23
61
|
it 'removes empty suffixed conditions before building' do
|
|
24
62
|
expect_any_instance_of(Search).to receive(:build).with({})
|
|
25
63
|
Search.new(Person, name_eq_any: [''])
|
|
@@ -109,6 +147,43 @@ module Ransack
|
|
|
109
147
|
expect(s.result.to_sql).to include 'published'
|
|
110
148
|
end
|
|
111
149
|
|
|
150
|
+
# The failure/oversight in Ransack::Nodes::Condition#arel_predicate or deeper is beyond my understanding of the structures
|
|
151
|
+
it 'preserves (inverts) default scope and conditions for negative subqueries' do
|
|
152
|
+
# the positive case (published_articles_title_eq) is
|
|
153
|
+
# SELECT "people".* FROM "people"
|
|
154
|
+
# LEFT OUTER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
|
155
|
+
# AND "articles"."published" = 't'
|
|
156
|
+
# AND ('default_scope' = 'default_scope')
|
|
157
|
+
# WHERE "articles"."title" = 'Test' ORDER BY "people"."id" DESC
|
|
158
|
+
#
|
|
159
|
+
# negative case was
|
|
160
|
+
# SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
|
|
161
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
162
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
163
|
+
# AND NOT ("articles"."title" != 'Test')
|
|
164
|
+
# ) ORDER BY "people"."id" DESC
|
|
165
|
+
#
|
|
166
|
+
# Should have been like
|
|
167
|
+
# SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
|
|
168
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
169
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
170
|
+
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
|
171
|
+
# ) ORDER BY "people"."id" DESC
|
|
172
|
+
#
|
|
173
|
+
# With tenanting (eg default_scope with column reference), NOT IN should be like
|
|
174
|
+
# SELECT "people".* FROM "people" WHERE "people"."tenant_id" = 'tenant_id' AND "people"."id" NOT IN (
|
|
175
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
176
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
177
|
+
# AND "articles"."tenant_id" = 'tenant_id'
|
|
178
|
+
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
|
179
|
+
# ) ORDER BY "people"."id" DESC
|
|
180
|
+
|
|
181
|
+
pending("spec should pass, but I do not know how/where to fix lib code")
|
|
182
|
+
s = Search.new(Person, published_articles_title_not_eq: 'Test')
|
|
183
|
+
expect(s.result.to_sql).to include 'default_scope'
|
|
184
|
+
expect(s.result.to_sql).to include 'published'
|
|
185
|
+
end
|
|
186
|
+
|
|
112
187
|
it 'discards empty conditions' do
|
|
113
188
|
s = Search.new(Person, children_name_eq: '')
|
|
114
189
|
condition = s.base[:children_name_eq]
|
|
@@ -189,7 +264,7 @@ module Ransack
|
|
|
189
264
|
context 'with an invalid condition' do
|
|
190
265
|
subject { Search.new(Person, unknown_attr_eq: 'Ernie') }
|
|
191
266
|
|
|
192
|
-
context 'when ignore_unknown_conditions is false' do
|
|
267
|
+
context 'when ignore_unknown_conditions configuration option is false' do
|
|
193
268
|
before do
|
|
194
269
|
Ransack.configure { |c| c.ignore_unknown_conditions = false }
|
|
195
270
|
end
|
|
@@ -197,13 +272,39 @@ module Ransack
|
|
|
197
272
|
specify { expect { subject }.to raise_error ArgumentError }
|
|
198
273
|
end
|
|
199
274
|
|
|
200
|
-
context 'when ignore_unknown_conditions is true' do
|
|
275
|
+
context 'when ignore_unknown_conditions configuration option is true' do
|
|
201
276
|
before do
|
|
202
277
|
Ransack.configure { |c| c.ignore_unknown_conditions = true }
|
|
203
278
|
end
|
|
204
279
|
|
|
205
280
|
specify { expect { subject }.not_to raise_error }
|
|
206
281
|
end
|
|
282
|
+
|
|
283
|
+
subject(:with_ignore_unknown_conditions_false) {
|
|
284
|
+
Search.new(Person,
|
|
285
|
+
{ unknown_attr_eq: 'Ernie' },
|
|
286
|
+
{ ignore_unknown_conditions: false }
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
subject(:with_ignore_unknown_conditions_true) {
|
|
291
|
+
Search.new(Person,
|
|
292
|
+
{ unknown_attr_eq: 'Ernie' },
|
|
293
|
+
{ ignore_unknown_conditions: true }
|
|
294
|
+
)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
context 'when ignore_unknown_conditions search parameter is absent' do
|
|
298
|
+
specify { expect { subject }.not_to raise_error }
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
context 'when ignore_unknown_conditions search parameter is false' do
|
|
302
|
+
specify { expect { with_ignore_unknown_conditions_false }.to raise_error ArgumentError }
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context 'when ignore_unknown_conditions search parameter is true' do
|
|
306
|
+
specify { expect { with_ignore_unknown_conditions_true }.not_to raise_error }
|
|
307
|
+
end
|
|
207
308
|
end
|
|
208
309
|
|
|
209
310
|
it 'does not modify the parameters' do
|
|
@@ -211,6 +312,29 @@ module Ransack
|
|
|
211
312
|
expect { Search.new(Person, params) }.not_to change { params }
|
|
212
313
|
end
|
|
213
314
|
|
|
315
|
+
context "ransackable_scope" do
|
|
316
|
+
around(:each) do |example|
|
|
317
|
+
Person.define_singleton_method(:name_eq) do |name|
|
|
318
|
+
self.where(name: name)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
begin
|
|
322
|
+
example.run
|
|
323
|
+
ensure
|
|
324
|
+
Person.singleton_class.undef_method :name_eq
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it "is prioritized over base predicates" do
|
|
329
|
+
allow(Person).to receive(:ransackable_scopes)
|
|
330
|
+
.and_return(Person.ransackable_scopes + [:name_eq])
|
|
331
|
+
|
|
332
|
+
s = Search.new(Person, name_eq: "Johny")
|
|
333
|
+
expect(s.instance_variable_get(:@scope_args)["name_eq"]).to eq("Johny")
|
|
334
|
+
expect(s.base[:name_eq]).to be_nil
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
214
338
|
end
|
|
215
339
|
|
|
216
340
|
describe '#result' do
|
|
@@ -220,6 +344,9 @@ module Ransack
|
|
|
220
344
|
let(:children_people_name_field) {
|
|
221
345
|
"#{quote_table_name("children_people")}.#{quote_column_name("name")}"
|
|
222
346
|
}
|
|
347
|
+
let(:notable_type_field) {
|
|
348
|
+
"#{quote_table_name("notes")}.#{quote_column_name("notable_type")}"
|
|
349
|
+
}
|
|
223
350
|
it 'evaluates conditions contextually' do
|
|
224
351
|
s = Search.new(Person, children_name_eq: 'Ernie')
|
|
225
352
|
expect(s.result).to be_an ActiveRecord::Relation
|
|
@@ -228,19 +355,20 @@ module Ransack
|
|
|
228
355
|
end
|
|
229
356
|
|
|
230
357
|
it 'use appropriate table alias' do
|
|
231
|
-
skip "Make this spec pass for Rails <5.2" if ::ActiveRecord::VERSION::STRING < '5.2.0'
|
|
232
358
|
s = Search.new(Person, {
|
|
233
359
|
name_eq: "person_name_query",
|
|
234
360
|
articles_title_eq: "person_article_title_query",
|
|
235
361
|
parent_name_eq: "parent_name_query",
|
|
236
362
|
parent_articles_title_eq: 'parents_article_title_query'
|
|
237
363
|
}).result
|
|
364
|
+
|
|
238
365
|
real_query = remove_quotes_and_backticks(s.to_sql)
|
|
239
366
|
|
|
240
367
|
expect(real_query)
|
|
241
|
-
|
|
368
|
+
.to match(%r{LEFT OUTER JOIN articles ON (\('default_scope' = 'default_scope'\) AND )?articles.person_id = people.id})
|
|
242
369
|
expect(real_query)
|
|
243
|
-
|
|
370
|
+
.to match(%r{LEFT OUTER JOIN articles articles_people ON (\('default_scope' = 'default_scope'\) AND )?articles_people.person_id = parents_people.id})
|
|
371
|
+
|
|
244
372
|
expect(real_query)
|
|
245
373
|
.to include "people.name = 'person_name_query'"
|
|
246
374
|
expect(real_query)
|
|
@@ -251,13 +379,7 @@ module Ransack
|
|
|
251
379
|
.to include "articles_people.title = 'parents_article_title_query'"
|
|
252
380
|
end
|
|
253
381
|
|
|
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'
|
|
382
|
+
it 'evaluates conditions for multiple `belongs_to` associations to the same table contextually' do
|
|
261
383
|
s = Search.new(
|
|
262
384
|
Recommendation,
|
|
263
385
|
person_name_eq: 'Ernie',
|
|
@@ -289,6 +411,7 @@ module Ransack
|
|
|
289
411
|
s = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie').result
|
|
290
412
|
expect(s).to be_an ActiveRecord::Relation
|
|
291
413
|
expect(s.to_sql).to match /#{people_name_field} = 'Ernie'/
|
|
414
|
+
expect(s.to_sql).to match /#{notable_type_field} = 'Person'/
|
|
292
415
|
end
|
|
293
416
|
|
|
294
417
|
it 'evaluates nested conditions' do
|
|
@@ -327,11 +450,8 @@ module Ransack
|
|
|
327
450
|
{ m: 'or', comments_body_cont: 'e', articles_comments_body_cont: 'e' }
|
|
328
451
|
]
|
|
329
452
|
)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
else
|
|
333
|
-
all_or_load, uniq_or_distinct = :load, :distinct
|
|
334
|
-
end
|
|
453
|
+
|
|
454
|
+
all_or_load, uniq_or_distinct = :load, :distinct
|
|
335
455
|
expect(s.result.send(all_or_load).size)
|
|
336
456
|
.to eq(9000)
|
|
337
457
|
expect(s.result(distinct: true).size)
|
|
@@ -384,88 +504,169 @@ module Ransack
|
|
|
384
504
|
expect(sort.dir).to eq 'asc'
|
|
385
505
|
end
|
|
386
506
|
|
|
387
|
-
it 'creates sorts based on
|
|
388
|
-
@s.sorts =
|
|
507
|
+
it 'creates sorts based on a single alias/direction' do
|
|
508
|
+
@s.sorts = 'daddy desc'
|
|
509
|
+
expect(@s.sorts.size).to eq(1)
|
|
510
|
+
sort = @s.sorts.first
|
|
511
|
+
expect(sort).to be_a Nodes::Sort
|
|
512
|
+
expect(sort.name).to eq 'parent_name'
|
|
513
|
+
expect(sort.dir).to eq 'desc'
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
it 'creates sorts based on a single alias and uppercase direction' do
|
|
517
|
+
@s.sorts = 'daddy DESC'
|
|
518
|
+
expect(@s.sorts.size).to eq(1)
|
|
519
|
+
sort = @s.sorts.first
|
|
520
|
+
expect(sort).to be_a Nodes::Sort
|
|
521
|
+
expect(sort.name).to eq 'parent_name'
|
|
522
|
+
expect(sort.dir).to eq 'desc'
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
it 'creates sorts based on a single alias and without direction' do
|
|
526
|
+
@s.sorts = 'daddy'
|
|
527
|
+
expect(@s.sorts.size).to eq(1)
|
|
528
|
+
sort = @s.sorts.first
|
|
529
|
+
expect(sort).to be_a Nodes::Sort
|
|
530
|
+
expect(sort.name).to eq 'parent_name'
|
|
531
|
+
expect(sort.dir).to eq 'asc'
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
it 'creates sorts based on attributes, alias and directions in array format' do
|
|
535
|
+
@s.sorts = ['id desc', { name: 'daddy', dir: 'asc' }]
|
|
389
536
|
expect(@s.sorts.size).to eq(2)
|
|
390
537
|
sort1, sort2 = @s.sorts
|
|
391
538
|
expect(sort1).to be_a Nodes::Sort
|
|
392
539
|
expect(sort1.name).to eq 'id'
|
|
393
540
|
expect(sort1.dir).to eq 'desc'
|
|
394
541
|
expect(sort2).to be_a Nodes::Sort
|
|
395
|
-
expect(sort2.name).to eq '
|
|
542
|
+
expect(sort2.name).to eq 'parent_name'
|
|
396
543
|
expect(sort2.dir).to eq 'asc'
|
|
397
544
|
end
|
|
398
545
|
|
|
399
|
-
it 'creates sorts based on
|
|
400
|
-
@s.sorts = ['id DESC', { name: '
|
|
546
|
+
it 'creates sorts based on attributes, alias and uppercase directions in array format' do
|
|
547
|
+
@s.sorts = ['id DESC', { name: 'daddy', dir: 'ASC' }]
|
|
401
548
|
expect(@s.sorts.size).to eq(2)
|
|
402
549
|
sort1, sort2 = @s.sorts
|
|
403
550
|
expect(sort1).to be_a Nodes::Sort
|
|
404
551
|
expect(sort1.name).to eq 'id'
|
|
405
552
|
expect(sort1.dir).to eq 'desc'
|
|
406
553
|
expect(sort2).to be_a Nodes::Sort
|
|
407
|
-
expect(sort2.name).to eq '
|
|
554
|
+
expect(sort2.name).to eq 'parent_name'
|
|
408
555
|
expect(sort2.dir).to eq 'asc'
|
|
409
556
|
end
|
|
410
557
|
|
|
411
|
-
it 'creates sorts based on
|
|
558
|
+
it 'creates sorts based on attributes, alias and different directions
|
|
412
559
|
in array format' do
|
|
413
|
-
@s.sorts = ['id DESC', { name: '
|
|
560
|
+
@s.sorts = ['id DESC', { name: 'daddy', dir: nil }]
|
|
414
561
|
expect(@s.sorts.size).to eq(2)
|
|
415
562
|
sort1, sort2 = @s.sorts
|
|
416
563
|
expect(sort1).to be_a Nodes::Sort
|
|
417
564
|
expect(sort1.name).to eq 'id'
|
|
418
565
|
expect(sort1.dir).to eq 'desc'
|
|
419
566
|
expect(sort2).to be_a Nodes::Sort
|
|
420
|
-
expect(sort2.name).to eq '
|
|
567
|
+
expect(sort2.name).to eq 'parent_name'
|
|
421
568
|
expect(sort2.dir).to eq 'asc'
|
|
422
569
|
end
|
|
423
570
|
|
|
424
|
-
it 'creates sorts based on
|
|
571
|
+
it 'creates sorts based on attributes, alias and directions in hash format' do
|
|
425
572
|
@s.sorts = {
|
|
426
573
|
'0' => { name: 'id', dir: 'desc' },
|
|
427
|
-
'1' => { name: '
|
|
574
|
+
'1' => { name: 'daddy', dir: 'asc' }
|
|
428
575
|
}
|
|
429
576
|
expect(@s.sorts.size).to eq(2)
|
|
430
577
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
|
431
578
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
|
432
|
-
|
|
579
|
+
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
|
433
580
|
expect(id_sort.dir).to eq 'desc'
|
|
434
|
-
expect(
|
|
581
|
+
expect(daddy_sort.dir).to eq 'asc'
|
|
435
582
|
end
|
|
436
583
|
|
|
437
|
-
it 'creates sorts based on
|
|
584
|
+
it 'creates sorts based on attributes, alias and uppercase directions
|
|
438
585
|
in hash format' do
|
|
439
586
|
@s.sorts = {
|
|
440
587
|
'0' => { name: 'id', dir: 'DESC' },
|
|
441
|
-
'1' => { name: '
|
|
588
|
+
'1' => { name: 'daddy', dir: 'ASC' }
|
|
442
589
|
}
|
|
443
590
|
expect(@s.sorts.size).to eq(2)
|
|
444
591
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
|
445
592
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
|
446
|
-
|
|
593
|
+
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
|
447
594
|
expect(id_sort.dir).to eq 'desc'
|
|
448
|
-
expect(
|
|
595
|
+
expect(daddy_sort.dir).to eq 'asc'
|
|
449
596
|
end
|
|
450
597
|
|
|
451
|
-
it 'creates sorts based on
|
|
598
|
+
it 'creates sorts based on attributes, alias and different directions
|
|
452
599
|
in hash format' do
|
|
453
600
|
@s.sorts = {
|
|
454
601
|
'0' => { name: 'id', dir: 'DESC' },
|
|
455
|
-
'1' => { name: '
|
|
602
|
+
'1' => { name: 'daddy', dir: nil }
|
|
456
603
|
}
|
|
457
604
|
expect(@s.sorts.size).to eq(2)
|
|
458
605
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
|
459
606
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
|
460
|
-
|
|
607
|
+
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
|
461
608
|
expect(id_sort.dir).to eq 'desc'
|
|
462
|
-
expect(
|
|
609
|
+
expect(daddy_sort.dir).to eq 'asc'
|
|
463
610
|
end
|
|
464
611
|
|
|
465
612
|
it 'overrides existing sort' do
|
|
466
613
|
@s.sorts = 'id asc'
|
|
467
614
|
expect(@s.result.first.id).to eq 1
|
|
468
615
|
end
|
|
616
|
+
|
|
617
|
+
it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
|
|
618
|
+
default = Ransack.options.clone
|
|
619
|
+
|
|
620
|
+
s = Search.new(Person, s: 'name asc')
|
|
621
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC"
|
|
622
|
+
|
|
623
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
|
|
624
|
+
s = Search.new(Person, s: 'name asc')
|
|
625
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS FIRST"
|
|
626
|
+
s = Search.new(Person, s: 'name desc')
|
|
627
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS LAST"
|
|
628
|
+
|
|
629
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_last }
|
|
630
|
+
s = Search.new(Person, s: 'name asc')
|
|
631
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS LAST"
|
|
632
|
+
s = Search.new(Person, s: 'name desc')
|
|
633
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS FIRST"
|
|
634
|
+
|
|
635
|
+
Ransack.options = default
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
it "PG's sort option with double name", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
|
|
639
|
+
default = Ransack.options.clone
|
|
640
|
+
|
|
641
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
642
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC"
|
|
643
|
+
|
|
644
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
|
|
645
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
646
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS FIRST"
|
|
647
|
+
s = Search.new(Person, s: 'doubled_name desc')
|
|
648
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS LAST"
|
|
649
|
+
|
|
650
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_last }
|
|
651
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
652
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS LAST"
|
|
653
|
+
s = Search.new(Person, s: 'doubled_name desc')
|
|
654
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS FIRST"
|
|
655
|
+
|
|
656
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_always_first }
|
|
657
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
658
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS FIRST"
|
|
659
|
+
s = Search.new(Person, s: 'doubled_name desc')
|
|
660
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS FIRST"
|
|
661
|
+
|
|
662
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_always_last }
|
|
663
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
664
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS LAST"
|
|
665
|
+
s = Search.new(Person, s: 'doubled_name desc')
|
|
666
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS LAST"
|
|
667
|
+
|
|
668
|
+
Ransack.options = default
|
|
669
|
+
end
|
|
469
670
|
end
|
|
470
671
|
|
|
471
672
|
describe '#method_missing' do
|
|
@@ -8,7 +8,7 @@ module Ransack
|
|
|
8
8
|
ar_translation = ::Namespace::Article.human_attribute_name(:title)
|
|
9
9
|
ransack_translation = Ransack::Translate.attribute(
|
|
10
10
|
:title,
|
|
11
|
-
:
|
|
11
|
+
context: ::Namespace::Article.ransack.context
|
|
12
12
|
)
|
|
13
13
|
expect(ransack_translation).to eq ar_translation
|
|
14
14
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
require 'machinist/active_record'
|
|
2
|
+
require 'polyamorous/polyamorous'
|
|
2
3
|
require 'sham'
|
|
3
4
|
require 'faker'
|
|
4
5
|
require 'ransack'
|
|
6
|
+
require 'action_controller'
|
|
7
|
+
require 'ransack/helpers'
|
|
5
8
|
require 'pry'
|
|
6
9
|
require 'simplecov'
|
|
7
10
|
require 'byebug'
|
|
@@ -14,16 +17,17 @@ I18n.load_path += Dir[File.join(File.dirname(__FILE__), 'support', '*.yml')]
|
|
|
14
17
|
Dir[File.expand_path('../{helpers,support,blueprints}/*.rb', __FILE__)]
|
|
15
18
|
.each { |f| require f }
|
|
16
19
|
|
|
20
|
+
Faker::Config.random = Random.new(0)
|
|
17
21
|
Sham.define do
|
|
18
22
|
name { Faker::Name.name }
|
|
19
23
|
title { Faker::Lorem.sentence }
|
|
20
24
|
body { Faker::Lorem.paragraph }
|
|
21
25
|
salary { |index| 30000 + (index * 1000) }
|
|
22
|
-
tag_name { Faker::Lorem.words(3).join(' ') }
|
|
23
|
-
note { Faker::Lorem.words(7).join(' ') }
|
|
24
|
-
only_admin { Faker::Lorem.words(3).join(' ') }
|
|
25
|
-
only_search { Faker::Lorem.words(3).join(' ') }
|
|
26
|
-
only_sort { Faker::Lorem.words(3).join(' ') }
|
|
26
|
+
tag_name { Faker::Lorem.words(number: 3).join(' ') }
|
|
27
|
+
note { Faker::Lorem.words(number: 7).join(' ') }
|
|
28
|
+
only_admin { Faker::Lorem.words(number: 3).join(' ') }
|
|
29
|
+
only_search { Faker::Lorem.words(number: 3).join(' ') }
|
|
30
|
+
only_sort { Faker::Lorem.words(number: 3).join(' ') }
|
|
27
31
|
notable_id { |id| id }
|
|
28
32
|
end
|
|
29
33
|
|