ransack 1.7.0 → 1.8.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/.travis.yml +40 -22
- data/CHANGELOG.md +176 -27
- data/CONTRIBUTING.md +30 -19
- data/Gemfile +8 -3
- data/README.md +131 -58
- data/Rakefile +5 -2
- data/lib/ransack.rb +10 -5
- data/lib/ransack/adapters.rb +43 -23
- data/lib/ransack/adapters/active_record.rb +2 -2
- data/lib/ransack/adapters/active_record/3.0/compat.rb +5 -5
- data/lib/ransack/adapters/active_record/3.0/context.rb +5 -3
- data/lib/ransack/adapters/active_record/3.1/context.rb +1 -4
- data/lib/ransack/adapters/active_record/base.rb +12 -1
- data/lib/ransack/adapters/active_record/context.rb +148 -55
- data/lib/ransack/adapters/active_record/ransack/constants.rb +53 -53
- data/lib/ransack/adapters/active_record/ransack/context.rb +3 -1
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +20 -28
- data/lib/ransack/adapters/mongoid/base.rb +21 -6
- data/lib/ransack/adapters/mongoid/context.rb +9 -5
- data/lib/ransack/configuration.rb +24 -3
- data/lib/ransack/constants.rb +11 -22
- data/lib/ransack/context.rb +20 -13
- data/lib/ransack/helpers/form_builder.rb +5 -6
- data/lib/ransack/helpers/form_helper.rb +50 -69
- data/lib/ransack/locale/da.yml +70 -0
- data/lib/ransack/locale/id.yml +70 -0
- data/lib/ransack/locale/ja.yml +70 -0
- data/lib/ransack/locale/pt-BR.yml +70 -0
- data/lib/ransack/locale/{zh.yml → zh-CN.yml} +1 -1
- data/lib/ransack/locale/zh-TW.yml +70 -0
- data/lib/ransack/nodes.rb +1 -1
- data/lib/ransack/nodes/attribute.rb +4 -1
- data/lib/ransack/nodes/bindable.rb +18 -6
- data/lib/ransack/nodes/condition.rb +58 -28
- data/lib/ransack/nodes/grouping.rb +15 -4
- data/lib/ransack/nodes/sort.rb +9 -5
- data/lib/ransack/predicate.rb +6 -2
- data/lib/ransack/search.rb +6 -5
- data/lib/ransack/translate.rb +2 -2
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +4 -4
- data/spec/mongoid/adapters/mongoid/base_spec.rb +20 -1
- data/spec/mongoid/nodes/condition_spec.rb +15 -0
- data/spec/mongoid/support/mongoid.yml +5 -0
- data/spec/mongoid/support/schema.rb +4 -0
- data/spec/mongoid_spec_helper.rb +13 -9
- data/spec/ransack/adapters/active_record/base_spec.rb +249 -71
- data/spec/ransack/adapters/active_record/context_spec.rb +16 -18
- data/spec/ransack/helpers/form_builder_spec.rb +5 -2
- data/spec/ransack/helpers/form_helper_spec.rb +84 -14
- data/spec/ransack/nodes/condition_spec.rb +24 -0
- data/spec/ransack/nodes/grouping_spec.rb +56 -0
- data/spec/ransack/predicate_spec.rb +5 -5
- data/spec/ransack/search_spec.rb +79 -70
- data/spec/support/schema.rb +43 -29
- metadata +17 -12
@@ -9,11 +9,11 @@ module Ransack
|
|
9
9
|
describe Context do
|
10
10
|
subject { Context.new(Person) }
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
|
13
|
+
it 'has an Active Record alias tracker method',
|
14
|
+
if: AR_version >= '3.1' do
|
15
|
+
expect(subject.alias_tracker)
|
16
|
+
.to be_an ::ActiveRecord::Associations::AliasTracker
|
17
17
|
end
|
18
18
|
|
19
19
|
describe '#relation_for' do
|
@@ -24,8 +24,8 @@ module Ransack
|
|
24
24
|
|
25
25
|
describe '#evaluate' do
|
26
26
|
it 'evaluates search objects' do
|
27
|
-
|
28
|
-
result = subject.evaluate(
|
27
|
+
s = Search.new(Person, name_eq: 'Joe Blow')
|
28
|
+
result = subject.evaluate(s)
|
29
29
|
|
30
30
|
expect(result).to be_an ::ActiveRecord::Relation
|
31
31
|
expect(result.to_sql)
|
@@ -33,25 +33,25 @@ module Ransack
|
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'SELECTs DISTINCT when distinct: true' do
|
36
|
-
|
37
|
-
result = subject.evaluate(
|
36
|
+
s = Search.new(Person, name_eq: 'Joe Blow')
|
37
|
+
result = subject.evaluate(s, distinct: true)
|
38
38
|
|
39
39
|
expect(result).to be_an ::ActiveRecord::Relation
|
40
40
|
expect(result.to_sql).to match /SELECT DISTINCT/
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
describe
|
44
|
+
describe 'sharing context across searches' do
|
45
45
|
let(:shared_context) { Context.for(Person) }
|
46
46
|
|
47
47
|
before do
|
48
|
-
Search.new(Person, { :
|
48
|
+
Search.new(Person, { parent_name_eq: 'A' },
|
49
49
|
context: shared_context)
|
50
|
-
Search.new(Person, { :
|
50
|
+
Search.new(Person, { children_name_eq: 'B' },
|
51
51
|
context: shared_context)
|
52
52
|
end
|
53
53
|
|
54
|
-
describe '#join_associations', :
|
54
|
+
describe '#join_associations', if: AR_version <= '4.0' do
|
55
55
|
it 'returns dependent join associations for all searches run
|
56
56
|
against the context' do
|
57
57
|
parents, children = shared_context.join_associations
|
@@ -69,18 +69,16 @@ module Ransack
|
|
69
69
|
end
|
70
70
|
|
71
71
|
describe '#join_sources' do
|
72
|
-
# FIXME: fix this test for Rails 4.2.
|
72
|
+
# FIXME: fix this test for Rails 4.2 and 5.0.
|
73
73
|
it 'returns dependent arel join nodes for all searches run against
|
74
|
-
the context',
|
75
|
-
:if => %w(3.1 3.2 4.0 4.1).include?(AR_version) do
|
74
|
+
the context', if: %w(3.1 3.2 4.0 4.1).include?(AR_version) do
|
76
75
|
parents, children = shared_context.join_sources
|
77
|
-
|
78
76
|
expect(children.left.name).to eq "children_people"
|
79
77
|
expect(parents.left.name).to eq "parents_people"
|
80
78
|
end
|
81
79
|
|
82
80
|
it 'can be rejoined to execute a valid query',
|
83
|
-
:
|
81
|
+
if: AR_version >= '3.1' do
|
84
82
|
parents, children = shared_context.join_sources
|
85
83
|
|
86
84
|
expect { Person.joins(parents).joins(children).to_a }
|
@@ -7,7 +7,6 @@ module Ransack
|
|
7
7
|
router = ActionDispatch::Routing::RouteSet.new
|
8
8
|
router.draw do
|
9
9
|
resources :people, :comments, :notes
|
10
|
-
get ':controller(/:action(/:id(.:format)))'
|
11
10
|
end
|
12
11
|
|
13
12
|
include router.url_helpers
|
@@ -22,7 +21,11 @@ module Ransack
|
|
22
21
|
@controller.view_context.search_form_for(@s) { |f| @f = f }
|
23
22
|
end
|
24
23
|
|
25
|
-
it 'selects previously-entered time values with datetime_select'
|
24
|
+
it 'selects previously-entered time values with datetime_select',
|
25
|
+
unless: (
|
26
|
+
RUBY_VERSION >= '2.3' &&
|
27
|
+
::ActiveRecord::VERSION::STRING.first(3) < '3.2'
|
28
|
+
) do
|
26
29
|
date_values = %w(2011 1 2 03 04 05)
|
27
30
|
# @s.created_at_eq = date_values # This works in Rails 4.x but not 3.x
|
28
31
|
@s.created_at_eq = [2011, 1, 2, 3, 4, 5] # so we have to do this
|
@@ -10,7 +10,6 @@ module Ransack
|
|
10
10
|
namespace :admin do
|
11
11
|
resources :comments
|
12
12
|
end
|
13
|
-
get ':controller(/:action(/:id(.:format)))'
|
14
13
|
end
|
15
14
|
|
16
15
|
include router.url_helpers
|
@@ -19,13 +18,8 @@ module Ransack
|
|
19
18
|
before do
|
20
19
|
@controller = ActionView::TestCase::TestController.new
|
21
20
|
@controller.instance_variable_set(:@_routes, router)
|
22
|
-
@controller.class_eval
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
@controller.view_context_class.class_eval do
|
27
|
-
include router.url_helpers
|
28
|
-
end
|
21
|
+
@controller.class_eval { include router.url_helpers }
|
22
|
+
@controller.view_context_class.class_eval { include router.url_helpers }
|
29
23
|
end
|
30
24
|
|
31
25
|
describe '#sort_link with default search_key' do
|
@@ -316,12 +310,13 @@ module Ransack
|
|
316
310
|
end
|
317
311
|
|
318
312
|
context 'view has existing parameters' do
|
319
|
-
|
320
|
-
@controller.view_context.params.merge!({ exist: 'existing' })
|
321
|
-
end
|
313
|
+
|
322
314
|
describe '#sort_link should not remove existing params' do
|
323
|
-
|
324
|
-
|
315
|
+
|
316
|
+
before { @controller.view_context.params[:exist] = 'existing' }
|
317
|
+
|
318
|
+
subject {
|
319
|
+
@controller.view_context.sort_link(
|
325
320
|
Person.search(
|
326
321
|
{ sorts: ['name desc'] },
|
327
322
|
search_key: 'people_search'
|
@@ -330,8 +325,44 @@ module Ransack
|
|
330
325
|
controller: 'people'
|
331
326
|
)
|
332
327
|
}
|
328
|
+
|
333
329
|
it { should match /exist\=existing/ }
|
334
330
|
end
|
331
|
+
|
332
|
+
context 'using a real ActionController::Parameter object',
|
333
|
+
if: ::ActiveRecord::VERSION::MAJOR > 3 do
|
334
|
+
|
335
|
+
describe 'with symbol q:, #sort_link should include search params' do
|
336
|
+
subject { @controller.view_context.sort_link(Person.search, :name) }
|
337
|
+
let(:params) { ActionController::Parameters.new(
|
338
|
+
{ :q => { name_eq: 'TEST' }, controller: 'people' }
|
339
|
+
) }
|
340
|
+
before { @controller.instance_variable_set(:@params, params) }
|
341
|
+
|
342
|
+
it {
|
343
|
+
should match(
|
344
|
+
/people\?q(%5B|\[)name_eq(%5D|\])=TEST&q(%5B|\[)s(%5D|\])
|
345
|
+
=name\+asc/x,
|
346
|
+
)
|
347
|
+
}
|
348
|
+
end
|
349
|
+
|
350
|
+
describe "with string 'q', #sort_link should include search params" do
|
351
|
+
subject { @controller.view_context.sort_link(Person.search, :name) }
|
352
|
+
let(:params) {
|
353
|
+
ActionController::Parameters.new(
|
354
|
+
{ 'q' => { name_eq: 'Test2' }, controller: 'people' }
|
355
|
+
) }
|
356
|
+
before { @controller.instance_variable_set(:@params, params) }
|
357
|
+
|
358
|
+
it {
|
359
|
+
should match(
|
360
|
+
/people\?q(%5B|\[)name_eq(%5D|\])=Test2&q(%5B|\[)s(%5D|\])
|
361
|
+
=name\+asc/x,
|
362
|
+
)
|
363
|
+
}
|
364
|
+
end
|
365
|
+
end
|
335
366
|
end
|
336
367
|
|
337
368
|
describe '#sort_link with hide order indicator set to true' do
|
@@ -344,6 +375,7 @@ module Ransack
|
|
344
375
|
)
|
345
376
|
}
|
346
377
|
it { should match /Full Name/ }
|
378
|
+
it { should_not match /▼|▲/ }
|
347
379
|
end
|
348
380
|
|
349
381
|
describe '#sort_link with hide order indicator set to false' do
|
@@ -358,6 +390,45 @@ module Ransack
|
|
358
390
|
it { should match /Full Name ▼/ }
|
359
391
|
end
|
360
392
|
|
393
|
+
describe '#sort_link with config set to globally hide order indicators' do
|
394
|
+
before do
|
395
|
+
Ransack.configure { |c| c.hide_sort_order_indicators = true }
|
396
|
+
end
|
397
|
+
subject { @controller.view_context
|
398
|
+
.sort_link(
|
399
|
+
[:main_app, Person.search(sorts: ['name desc'])],
|
400
|
+
:name,
|
401
|
+
controller: 'people'
|
402
|
+
)
|
403
|
+
}
|
404
|
+
it { should_not match /▼|▲/ }
|
405
|
+
end
|
406
|
+
|
407
|
+
describe '#sort_link with config set to globally show order indicators' do
|
408
|
+
before do
|
409
|
+
Ransack.configure { |c| c.hide_sort_order_indicators = false }
|
410
|
+
end
|
411
|
+
subject { @controller.view_context
|
412
|
+
.sort_link(
|
413
|
+
[:main_app, Person.search(sorts: ['name desc'])],
|
414
|
+
:name,
|
415
|
+
controller: 'people'
|
416
|
+
)
|
417
|
+
}
|
418
|
+
it { should match /Full Name ▼/ }
|
419
|
+
end
|
420
|
+
|
421
|
+
describe '#sort_link with a block' do
|
422
|
+
subject { @controller.view_context
|
423
|
+
.sort_link(
|
424
|
+
[:main_app, Person.search(sorts: ['name desc'])],
|
425
|
+
:name,
|
426
|
+
controller: 'people'
|
427
|
+
) { 'Block label' }
|
428
|
+
}
|
429
|
+
it { should match /Block label ▼/ }
|
430
|
+
end
|
431
|
+
|
361
432
|
describe '#search_form_for with default format' do
|
362
433
|
subject { @controller.view_context
|
363
434
|
.search_form_for(Person.search) {} }
|
@@ -398,7 +469,6 @@ module Ransack
|
|
398
469
|
}
|
399
470
|
it { should match /example_name_eq/ }
|
400
471
|
end
|
401
|
-
|
402
472
|
end
|
403
473
|
end
|
404
474
|
end
|
@@ -4,6 +4,21 @@ module Ransack
|
|
4
4
|
module Nodes
|
5
5
|
describe Condition do
|
6
6
|
|
7
|
+
context 'with an alias' do
|
8
|
+
subject {
|
9
|
+
Condition.extract(
|
10
|
+
Context.for(Person), 'term_start', Person.first(2).map(&:name)
|
11
|
+
)
|
12
|
+
}
|
13
|
+
|
14
|
+
specify { expect(subject.combinator).to eq 'or' }
|
15
|
+
specify { expect(subject.predicate.name).to eq 'start' }
|
16
|
+
|
17
|
+
it 'converts the alias to the correct attributes' do
|
18
|
+
expect(subject.attributes.map(&:name)).to eq(['name', 'email'])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
7
22
|
context 'with multiple values and an _any predicate' do
|
8
23
|
subject {
|
9
24
|
Condition.extract(
|
@@ -14,6 +29,15 @@ module Ransack
|
|
14
29
|
specify { expect(subject.values.size).to eq(2) }
|
15
30
|
end
|
16
31
|
|
32
|
+
describe '#negative?' do
|
33
|
+
let(:context) { Context.for(Person) }
|
34
|
+
let(:eq) { Condition.extract(context, 'name_eq', 'A') }
|
35
|
+
let(:not_eq) { Condition.extract(context, 'name_not_eq', 'A') }
|
36
|
+
|
37
|
+
specify { expect(not_eq.negative?).to be true }
|
38
|
+
specify { expect(eq.negative?).to be false }
|
39
|
+
end
|
40
|
+
|
17
41
|
context 'with an invalid predicate' do
|
18
42
|
subject {
|
19
43
|
Condition.extract(
|
@@ -50,6 +50,62 @@ module Ransack
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
describe '#conditions=' do
|
54
|
+
context 'when conditions are identical' do
|
55
|
+
let(:conditions) do
|
56
|
+
{
|
57
|
+
'0' => {
|
58
|
+
'a' => { '0'=> { 'name' => 'name', 'ransacker_args' => '' } },
|
59
|
+
'p' => 'cont',
|
60
|
+
'v' => { '0' => { 'value' => 'John' } }
|
61
|
+
},
|
62
|
+
'1' => {
|
63
|
+
'a' => { '0' => { 'name' => 'name', 'ransacker_args' => '' } },
|
64
|
+
'p' => 'cont',
|
65
|
+
'v' => { '0' => { 'value' => 'John' } }
|
66
|
+
}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
before { subject.conditions = conditions }
|
70
|
+
|
71
|
+
it 'expect duplicates to be removed' do
|
72
|
+
expect(subject.conditions.count).to eq 1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when conditions differ only by ransacker_args' do
|
77
|
+
let(:conditions) do
|
78
|
+
{
|
79
|
+
'0' => {
|
80
|
+
'a' => {
|
81
|
+
'0' => {
|
82
|
+
'name' => 'with_arguments',
|
83
|
+
'ransacker_args' => [1,2]
|
84
|
+
}
|
85
|
+
},
|
86
|
+
'p' => 'eq',
|
87
|
+
'v' => { '0' => { 'value' => '10' } }
|
88
|
+
},
|
89
|
+
'1' => {
|
90
|
+
'a' => {
|
91
|
+
'0' => {
|
92
|
+
'name' => 'with_arguments',
|
93
|
+
'ransacker_args' => [3,4]
|
94
|
+
}
|
95
|
+
},
|
96
|
+
'p' => 'eq',
|
97
|
+
'v' => { '0' => { 'value' => '10' } }
|
98
|
+
}
|
99
|
+
}
|
100
|
+
end
|
101
|
+
before { subject.conditions = conditions }
|
102
|
+
|
103
|
+
it 'expect them to be parsed as different and not as duplicates' do
|
104
|
+
expect(subject.conditions.count).to eq 2
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
53
109
|
end
|
54
110
|
end
|
55
111
|
end
|
@@ -16,7 +16,7 @@ module Ransack
|
|
16
16
|
expect { subject.result }.to_not raise_error
|
17
17
|
end
|
18
18
|
|
19
|
-
it "escapes '%', '.' and '\\\\' in value" do
|
19
|
+
it "escapes '%', '.', '_' and '\\\\' in value" do
|
20
20
|
subject.send(:"#{method}=", '%._\\')
|
21
21
|
expect(subject.result.to_sql).to match(regexp)
|
22
22
|
end
|
@@ -124,9 +124,9 @@ module Ransack
|
|
124
124
|
describe 'cont' do
|
125
125
|
it_has_behavior 'wildcard escaping', :name_cont,
|
126
126
|
(if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
127
|
-
/"people"."name" ILIKE '
|
127
|
+
/"people"."name" ILIKE '%\\%\\.\\_\\\\%'/
|
128
128
|
elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
|
129
|
-
/`people`.`name` LIKE '
|
129
|
+
/`people`.`name` LIKE '%\\\\%\\\\.\\\\_\\\\\\\\%'/
|
130
130
|
else
|
131
131
|
/"people"."name" LIKE '%%._\\%'/
|
132
132
|
end) do
|
@@ -143,9 +143,9 @@ module Ransack
|
|
143
143
|
describe 'not_cont' do
|
144
144
|
it_has_behavior 'wildcard escaping', :name_not_cont,
|
145
145
|
(if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
146
|
-
/"people"."name" NOT ILIKE '
|
146
|
+
/"people"."name" NOT ILIKE '%\\%\\.\\_\\\\%'/
|
147
147
|
elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
|
148
|
-
/`people`.`name` NOT LIKE '
|
148
|
+
/`people`.`name` NOT LIKE '%\\\\%\\\\.\\\\_\\\\\\\\%'/
|
149
149
|
else
|
150
150
|
/"people"."name" NOT LIKE '%%._\\%'/
|
151
151
|
end) do
|
data/spec/ransack/search_spec.rb
CHANGED
@@ -43,16 +43,16 @@ module Ransack
|
|
43
43
|
|
44
44
|
it 'accepts a context option' do
|
45
45
|
shared_context = Context.for(Person)
|
46
|
-
|
47
|
-
|
48
|
-
expect(
|
46
|
+
s1 = Search.new(Person, { name_eq: 'A' }, context: shared_context)
|
47
|
+
s2 = Search.new(Person, { name_eq: 'B' }, context: shared_context)
|
48
|
+
expect(s1.context).to be s2.context
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
describe '#build' do
|
53
53
|
it 'creates conditions for top-level attributes' do
|
54
|
-
|
55
|
-
condition =
|
54
|
+
s = Search.new(Person, name_eq: 'Ernie')
|
55
|
+
condition = s.base[:name_eq]
|
56
56
|
expect(condition).to be_a Nodes::Condition
|
57
57
|
expect(condition.predicate.name).to eq 'eq'
|
58
58
|
expect(condition.attributes.first.name).to eq 'name'
|
@@ -60,8 +60,8 @@ module Ransack
|
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'creates conditions for association attributes' do
|
63
|
-
|
64
|
-
condition =
|
63
|
+
s = Search.new(Person, children_name_eq: 'Ernie')
|
64
|
+
condition = s.base[:children_name_eq]
|
65
65
|
expect(condition).to be_a Nodes::Condition
|
66
66
|
expect(condition.predicate.name).to eq 'eq'
|
67
67
|
expect(condition.attributes.first.name).to eq 'children_name'
|
@@ -69,8 +69,8 @@ module Ransack
|
|
69
69
|
end
|
70
70
|
|
71
71
|
it 'creates conditions for polymorphic belongs_to association attributes' do
|
72
|
-
|
73
|
-
condition =
|
72
|
+
s = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie')
|
73
|
+
condition = s.base[:notable_of_Person_type_name_eq]
|
74
74
|
expect(condition).to be_a Nodes::Condition
|
75
75
|
expect(condition.predicate.name).to eq 'eq'
|
76
76
|
expect(condition.attributes.first.name)
|
@@ -80,9 +80,9 @@ module Ransack
|
|
80
80
|
|
81
81
|
it 'creates conditions for multiple polymorphic belongs_to association
|
82
82
|
attributes' do
|
83
|
-
|
83
|
+
s = Search.new(Note,
|
84
84
|
notable_of_Person_type_name_or_notable_of_Article_type_title_eq: 'Ernie')
|
85
|
-
condition =
|
85
|
+
condition = s.
|
86
86
|
base[:notable_of_Person_type_name_or_notable_of_Article_type_title_eq]
|
87
87
|
expect(condition).to be_a Nodes::Condition
|
88
88
|
expect(condition.predicate.name).to eq 'eq'
|
@@ -93,15 +93,25 @@ module Ransack
|
|
93
93
|
expect(condition.value).to eq 'Ernie'
|
94
94
|
end
|
95
95
|
|
96
|
+
it 'creates conditions for aliased attributes',
|
97
|
+
if: Ransack::SUPPORTS_ATTRIBUTE_ALIAS do
|
98
|
+
s = Search.new(Person, full_name_eq: 'Ernie')
|
99
|
+
condition = s.base[:full_name_eq]
|
100
|
+
expect(condition).to be_a Nodes::Condition
|
101
|
+
expect(condition.predicate.name).to eq 'eq'
|
102
|
+
expect(condition.attributes.first.name).to eq 'full_name'
|
103
|
+
expect(condition.value).to eq 'Ernie'
|
104
|
+
end
|
105
|
+
|
96
106
|
it 'preserves default scope and conditions for associations' do
|
97
|
-
|
98
|
-
expect(
|
99
|
-
expect(
|
107
|
+
s = Search.new(Person, published_articles_title_eq: 'Test')
|
108
|
+
expect(s.result.to_sql).to include 'default_scope'
|
109
|
+
expect(s.result.to_sql).to include 'published'
|
100
110
|
end
|
101
111
|
|
102
112
|
it 'discards empty conditions' do
|
103
|
-
|
104
|
-
condition =
|
113
|
+
s = Search.new(Person, children_name_eq: '')
|
114
|
+
condition = s.base[:children_name_eq]
|
105
115
|
expect(condition).to be_nil
|
106
116
|
end
|
107
117
|
|
@@ -111,13 +121,13 @@ module Ransack
|
|
111
121
|
end
|
112
122
|
|
113
123
|
it 'accepts arrays of groupings' do
|
114
|
-
|
124
|
+
s = Search.new(Person,
|
115
125
|
g: [
|
116
126
|
{ m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' },
|
117
127
|
{ m: 'or', name_eq: 'Bert', children_name_eq: 'Bert' },
|
118
128
|
]
|
119
129
|
)
|
120
|
-
ors =
|
130
|
+
ors = s.groupings
|
121
131
|
expect(ors.size).to eq(2)
|
122
132
|
or1, or2 = ors
|
123
133
|
expect(or1).to be_a Nodes::Grouping
|
@@ -126,14 +136,14 @@ module Ransack
|
|
126
136
|
expect(or2.combinator).to eq 'or'
|
127
137
|
end
|
128
138
|
|
129
|
-
it 'accepts
|
130
|
-
|
139
|
+
it 'accepts attributes hashes for groupings' do
|
140
|
+
s = Search.new(Person,
|
131
141
|
g: {
|
132
142
|
'0' => { m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' },
|
133
143
|
'1' => { m: 'or', name_eq: 'Bert', children_name_eq: 'Bert' },
|
134
144
|
}
|
135
145
|
)
|
136
|
-
ors =
|
146
|
+
ors = s.groupings
|
137
147
|
expect(ors.size).to eq(2)
|
138
148
|
or1, or2 = ors
|
139
149
|
expect(or1).to be_a Nodes::Grouping
|
@@ -142,8 +152,8 @@ module Ransack
|
|
142
152
|
expect(or2.combinator).to eq 'or'
|
143
153
|
end
|
144
154
|
|
145
|
-
it 'accepts
|
146
|
-
|
155
|
+
it 'accepts attributes hashes for conditions' do
|
156
|
+
s = Search.new(Person,
|
147
157
|
c: {
|
148
158
|
'0' => { a: ['name'], p: 'eq', v: ['Ernie'] },
|
149
159
|
'1' => {
|
@@ -152,7 +162,7 @@ module Ransack
|
|
152
162
|
}
|
153
163
|
}
|
154
164
|
)
|
155
|
-
conditions =
|
165
|
+
conditions = s.base.conditions
|
156
166
|
expect(conditions.size).to eq(2)
|
157
167
|
expect(conditions.map { |c| c.class })
|
158
168
|
.to eq [Nodes::Condition, Nodes::Condition]
|
@@ -163,8 +173,8 @@ module Ransack
|
|
163
173
|
config.add_predicate 'ary_pred', wants_array: true
|
164
174
|
end
|
165
175
|
|
166
|
-
|
167
|
-
condition =
|
176
|
+
s = Search.new(Person, name_ary_pred: ['Ernie', 'Bert'])
|
177
|
+
condition = s.base[:name_ary_pred]
|
168
178
|
expect(condition).to be_a Nodes::Condition
|
169
179
|
expect(condition.predicate.name).to eq 'ary_pred'
|
170
180
|
expect(condition.attributes.first.name).to eq 'name'
|
@@ -172,8 +182,8 @@ module Ransack
|
|
172
182
|
end
|
173
183
|
|
174
184
|
it 'does not evaluate the query on #inspect' do
|
175
|
-
|
176
|
-
expect(
|
185
|
+
s = Search.new(Person, children_id_in: [1, 2, 3])
|
186
|
+
expect(s.inspect).not_to match /ActiveRecord/
|
177
187
|
end
|
178
188
|
|
179
189
|
context 'with an invalid condition' do
|
@@ -211,9 +221,9 @@ module Ransack
|
|
211
221
|
"#{quote_table_name("children_people")}.#{quote_column_name("name")}"
|
212
222
|
}
|
213
223
|
it 'evaluates conditions contextually' do
|
214
|
-
|
215
|
-
expect(
|
216
|
-
expect(
|
224
|
+
s = Search.new(Person, children_name_eq: 'Ernie')
|
225
|
+
expect(s.result).to be_an ActiveRecord::Relation
|
226
|
+
expect(s.result.to_sql).to match /#{
|
217
227
|
children_people_name_field} = 'Ernie'/
|
218
228
|
end
|
219
229
|
|
@@ -221,51 +231,50 @@ module Ransack
|
|
221
231
|
# commenting out lines 221 and 242 to run the test. Addresses issue #374.
|
222
232
|
# https://github.com/activerecord-hackery/ransack/issues/374
|
223
233
|
#
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
234
|
+
it 'evaluates conditions for multiple `belongs_to` associations to the
|
235
|
+
same table contextually',
|
236
|
+
if: ::ActiveRecord::VERSION::STRING.first(3) == '4.0' do
|
237
|
+
s = Search.new(
|
238
|
+
Recommendation,
|
239
|
+
person_name_eq: 'Ernie',
|
240
|
+
target_person_parent_name_eq: 'Test'
|
241
|
+
).result
|
242
|
+
expect(s).to be_an ActiveRecord::Relation
|
243
|
+
real_query = remove_quotes_and_backticks(s.to_sql)
|
244
|
+
expected_query = <<-SQL
|
245
|
+
SELECT recommendations.* FROM recommendations
|
246
|
+
LEFT OUTER JOIN people ON people.id = recommendations.person_id
|
247
|
+
LEFT OUTER JOIN people target_people_recommendations
|
248
|
+
ON target_people_recommendations.id = recommendations.target_person_id
|
249
|
+
LEFT OUTER JOIN people parents_people
|
250
|
+
ON parents_people.id = target_people_recommendations.parent_id
|
251
|
+
WHERE ((people.name = 'Ernie' AND parents_people.name = 'Test'))
|
252
|
+
SQL
|
253
|
+
.squish
|
254
|
+
expect(real_query).to eq expected_query
|
245
255
|
end
|
246
256
|
|
247
257
|
it 'evaluates compound conditions contextually' do
|
248
|
-
|
249
|
-
expect(
|
250
|
-
expect(
|
258
|
+
s = Search.new(Person, children_name_or_name_eq: 'Ernie').result
|
259
|
+
expect(s).to be_an ActiveRecord::Relation
|
260
|
+
expect(s.to_sql).to match /#{children_people_name_field
|
251
261
|
} = 'Ernie' OR #{people_name_field} = 'Ernie'/
|
252
262
|
end
|
253
263
|
|
254
264
|
it 'evaluates polymorphic belongs_to association conditions contextually' do
|
255
|
-
|
256
|
-
.
|
257
|
-
expect(
|
258
|
-
expect(search.to_sql).to match /#{people_name_field} = 'Ernie'/
|
265
|
+
s = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie').result
|
266
|
+
expect(s).to be_an ActiveRecord::Relation
|
267
|
+
expect(s.to_sql).to match /#{people_name_field} = 'Ernie'/
|
259
268
|
end
|
260
269
|
|
261
270
|
it 'evaluates nested conditions' do
|
262
|
-
|
271
|
+
s = Search.new(Person, children_name_eq: 'Ernie',
|
263
272
|
g: [
|
264
273
|
{ m: 'or', name_eq: 'Ernie', children_children_name_eq: 'Ernie' }
|
265
274
|
]
|
266
275
|
).result
|
267
|
-
expect(
|
268
|
-
first, last =
|
276
|
+
expect(s).to be_an ActiveRecord::Relation
|
277
|
+
first, last = s.to_sql.split(/ AND /)
|
269
278
|
expect(first).to match /#{children_people_name_field} = 'Ernie'/
|
270
279
|
expect(last).to match /#{
|
271
280
|
people_name_field} = 'Ernie' OR #{
|
@@ -274,14 +283,14 @@ module Ransack
|
|
274
283
|
end
|
275
284
|
|
276
285
|
it 'evaluates arrays of groupings' do
|
277
|
-
|
286
|
+
s = Search.new(Person,
|
278
287
|
g: [
|
279
288
|
{ m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' },
|
280
289
|
{ m: 'or', name_eq: 'Bert', children_name_eq: 'Bert' }
|
281
290
|
]
|
282
291
|
).result
|
283
|
-
expect(
|
284
|
-
first, last =
|
292
|
+
expect(s).to be_an ActiveRecord::Relation
|
293
|
+
first, last = s.to_sql.split(/ AND /)
|
285
294
|
expect(first).to match /#{people_name_field} = 'Ernie' OR #{
|
286
295
|
children_people_name_field} = 'Ernie'/
|
287
296
|
expect(last).to match /#{people_name_field} = 'Bert' OR #{
|
@@ -289,7 +298,7 @@ module Ransack
|
|
289
298
|
end
|
290
299
|
|
291
300
|
it 'returns distinct records when passed distinct: true' do
|
292
|
-
|
301
|
+
s = Search.new(Person,
|
293
302
|
g: [
|
294
303
|
{ m: 'or', comments_body_cont: 'e', articles_comments_body_cont: 'e' }
|
295
304
|
]
|
@@ -299,12 +308,12 @@ module Ransack
|
|
299
308
|
else
|
300
309
|
all_or_load, uniq_or_distinct = :load, :distinct
|
301
310
|
end
|
302
|
-
expect(
|
311
|
+
expect(s.result.send(all_or_load).size)
|
303
312
|
.to eq(9000)
|
304
|
-
expect(
|
313
|
+
expect(s.result(distinct: true).size)
|
305
314
|
.to eq(10)
|
306
|
-
expect(
|
307
|
-
.to eq
|
315
|
+
expect(s.result.send(all_or_load).send(uniq_or_distinct))
|
316
|
+
.to eq s.result(distinct: true).send(all_or_load)
|
308
317
|
end
|
309
318
|
|
310
319
|
private
|