ransack 1.6.4 → 1.6.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -11
- data/CHANGELOG.md +50 -10
- data/CONTRIBUTING.md +29 -18
- data/README.md +9 -31
- data/lib/ransack/adapters/active_record/context.rb +22 -17
- data/lib/ransack/adapters/active_record/ransack/context.rb +1 -1
- data/lib/ransack/predicate.rb +2 -2
- data/lib/ransack/translate.rb +0 -5
- data/lib/ransack/version.rb +1 -1
- data/spec/mongoid/configuration_spec.rb +36 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +7 -6
- data/spec/ransack/configuration_spec.rb +36 -0
- data/spec/ransack/helpers/form_helper_spec.rb +65 -58
- data/spec/ransack/search_spec.rb +134 -104
- data/spec/spec_helper.rb +3 -4
- data/spec/support/schema.rb +36 -23
- metadata +2 -2
@@ -64,5 +64,41 @@ module Ransack
|
|
64
64
|
expect(Ransack.predicates).not_to have_key 'test_array_predicate_any'
|
65
65
|
expect(Ransack.predicates).not_to have_key 'test_array_predicate_all'
|
66
66
|
end
|
67
|
+
|
68
|
+
describe '`wants_array` option takes precedence over Arel predicate' do
|
69
|
+
it 'implicitly wants an array for in/not in predicates' do
|
70
|
+
Ransack.configure do |config|
|
71
|
+
config.add_predicate(
|
72
|
+
:test_in_predicate,
|
73
|
+
:arel_predicate => 'in'
|
74
|
+
)
|
75
|
+
config.add_predicate(
|
76
|
+
:test_not_in_predicate,
|
77
|
+
:arel_predicate => 'not_in'
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
expect(Ransack.predicates['test_in_predicate'].wants_array).to eq true
|
82
|
+
expect(Ransack.predicates['test_not_in_predicate'].wants_array).to eq true
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'explicitly does not want array for in/not_in predicates' do
|
86
|
+
Ransack.configure do |config|
|
87
|
+
config.add_predicate(
|
88
|
+
:test_in_predicate_no_array,
|
89
|
+
:arel_predicate => 'in',
|
90
|
+
:wants_array => false
|
91
|
+
)
|
92
|
+
config.add_predicate(
|
93
|
+
:test_not_in_predicate_no_array,
|
94
|
+
:arel_predicate => 'not_in',
|
95
|
+
:wants_array => false
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
expect(Ransack.predicates['test_in_predicate_no_array'].wants_array).to eq false
|
100
|
+
expect(Ransack.predicates['test_not_in_predicate_no_array'].wants_array).to eq false
|
101
|
+
end
|
102
|
+
end
|
67
103
|
end
|
68
104
|
end
|
@@ -31,9 +31,9 @@ module Ransack
|
|
31
31
|
describe '#sort_link with default search_key' do
|
32
32
|
subject { @controller.view_context
|
33
33
|
.sort_link(
|
34
|
-
[:main_app, Person.search(:
|
34
|
+
[:main_app, Person.search(sorts: ['name desc'])],
|
35
35
|
:name,
|
36
|
-
:
|
36
|
+
controller: 'people'
|
37
37
|
)
|
38
38
|
}
|
39
39
|
it {
|
@@ -53,10 +53,10 @@ module Ransack
|
|
53
53
|
subject { @controller.view_context
|
54
54
|
.sort_link(
|
55
55
|
Person.search(
|
56
|
-
{ :
|
56
|
+
{ sorts: ['name desc'] }, search_key: :people_search
|
57
57
|
),
|
58
58
|
:name,
|
59
|
-
:
|
59
|
+
controller: 'people'
|
60
60
|
)
|
61
61
|
}
|
62
62
|
it {
|
@@ -73,10 +73,11 @@ module Ransack
|
|
73
73
|
describe '#sort_link desc through association table defined as a symbol' do
|
74
74
|
subject { @controller.view_context
|
75
75
|
.sort_link(
|
76
|
-
Person.search({ :
|
77
|
-
:comments_body,
|
78
|
-
|
79
|
-
|
76
|
+
Person.search({ sorts: 'comments_body asc' }),
|
77
|
+
:comments_body,
|
78
|
+
controller: 'people'
|
79
|
+
)
|
80
|
+
}
|
80
81
|
it {
|
81
82
|
should match(
|
82
83
|
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
|
@@ -93,10 +94,11 @@ module Ransack
|
|
93
94
|
describe '#sort_link through association table defined as a string' do
|
94
95
|
subject { @controller.view_context
|
95
96
|
.sort_link(
|
96
|
-
Person.search({ :
|
97
|
-
'comments.body',
|
98
|
-
|
99
|
-
|
97
|
+
Person.search({ sorts: 'comments.body desc' }),
|
98
|
+
'comments.body',
|
99
|
+
controller: 'people'
|
100
|
+
)
|
101
|
+
}
|
100
102
|
it {
|
101
103
|
should match(
|
102
104
|
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
|
@@ -113,24 +115,25 @@ module Ransack
|
|
113
115
|
describe '#sort_link works even if search params are a blank string' do
|
114
116
|
before { @controller.view_context.params[:q] = '' }
|
115
117
|
specify {
|
116
|
-
expect {
|
117
|
-
|
118
|
-
Person.search(
|
119
|
-
|
120
|
-
|
121
|
-
|
118
|
+
expect { @controller.view_context
|
119
|
+
.sort_link(
|
120
|
+
Person.search(
|
121
|
+
@controller.view_context.params[:q]),
|
122
|
+
:name,
|
123
|
+
controller: 'people'
|
124
|
+
)
|
122
125
|
}.not_to raise_error
|
123
126
|
}
|
124
127
|
end
|
125
128
|
|
126
129
|
describe '#sort_link with search_key defined as a string' do
|
127
|
-
subject {
|
128
|
-
|
130
|
+
subject { @controller.view_context
|
131
|
+
.sort_link(
|
129
132
|
Person.search(
|
130
|
-
{ :
|
131
|
-
|
133
|
+
{ sorts: ['name desc'] }, search_key: 'people_search'
|
134
|
+
),
|
132
135
|
:name,
|
133
|
-
:
|
136
|
+
controller: 'people'
|
134
137
|
)
|
135
138
|
}
|
136
139
|
it {
|
@@ -149,8 +152,8 @@ module Ransack
|
|
149
152
|
.sort_link(
|
150
153
|
[:main_app, Person.search()],
|
151
154
|
:name,
|
152
|
-
:
|
153
|
-
|
155
|
+
controller: 'people',
|
156
|
+
default_order: 'desc'
|
154
157
|
)
|
155
158
|
}
|
156
159
|
it { should_not match /default_order/ }
|
@@ -159,9 +162,9 @@ module Ransack
|
|
159
162
|
describe '#sort_link with multiple search_keys defined as an array' do
|
160
163
|
subject { @controller.view_context
|
161
164
|
.sort_link(
|
162
|
-
[:main_app, Person.search(:
|
165
|
+
[:main_app, Person.search(sorts: ['name desc', 'email asc'])],
|
163
166
|
:name, [:name, 'email DESC'],
|
164
|
-
:
|
167
|
+
controller: 'people'
|
165
168
|
)
|
166
169
|
}
|
167
170
|
it {
|
@@ -176,9 +179,9 @@ module Ransack
|
|
176
179
|
describe '#sort_link with multiple search_keys does not break on nil values & ignores them' do
|
177
180
|
subject { @controller.view_context
|
178
181
|
.sort_link(
|
179
|
-
[:main_app, Person.search(:
|
182
|
+
[:main_app, Person.search(sorts: ['name desc', nil, 'email', nil])],
|
180
183
|
:name, [nil, :name, nil, 'email DESC', nil],
|
181
|
-
:
|
184
|
+
controller: 'people'
|
182
185
|
)
|
183
186
|
}
|
184
187
|
it {
|
@@ -193,10 +196,10 @@ module Ransack
|
|
193
196
|
describe '#sort_link with multiple search_keys should allow a label to be specified' do
|
194
197
|
subject { @controller.view_context
|
195
198
|
.sort_link(
|
196
|
-
[:main_app, Person.search(:
|
199
|
+
[:main_app, Person.search(sorts: ['name desc', 'email asc'])],
|
197
200
|
:name, [:name, 'email DESC'],
|
198
201
|
'Property Name',
|
199
|
-
:
|
202
|
+
controller: 'people'
|
200
203
|
)
|
201
204
|
}
|
202
205
|
it { should match /Property Name ▼/ }
|
@@ -205,9 +208,9 @@ module Ransack
|
|
205
208
|
describe '#sort_link with multiple search_keys should flip multiple fields specified without a direction' do
|
206
209
|
subject { @controller.view_context
|
207
210
|
.sort_link(
|
208
|
-
[:main_app, Person.search(:
|
211
|
+
[:main_app, Person.search(sorts: ['name desc', 'email asc'])],
|
209
212
|
:name, [:name, :email],
|
210
|
-
:
|
213
|
+
controller: 'people'
|
211
214
|
)
|
212
215
|
}
|
213
216
|
it {
|
@@ -224,8 +227,8 @@ module Ransack
|
|
224
227
|
.sort_link(
|
225
228
|
[:main_app, Person.search()],
|
226
229
|
:name, [:name, :email],
|
227
|
-
:
|
228
|
-
|
230
|
+
controller: 'people',
|
231
|
+
default_order: 'desc'
|
229
232
|
)
|
230
233
|
}
|
231
234
|
it {
|
@@ -242,8 +245,8 @@ module Ransack
|
|
242
245
|
.sort_link(
|
243
246
|
[:main_app, Person.search()],
|
244
247
|
:name, [:name, :email],
|
245
|
-
:
|
246
|
-
:
|
248
|
+
controller: 'people',
|
249
|
+
default_order: :desc
|
247
250
|
)
|
248
251
|
}
|
249
252
|
it {
|
@@ -260,8 +263,8 @@ module Ransack
|
|
260
263
|
.sort_link(
|
261
264
|
[:main_app, Person.search()],
|
262
265
|
:name, [:name, :email],
|
263
|
-
:
|
264
|
-
:
|
266
|
+
controller: 'people',
|
267
|
+
default_order: { name: 'desc', email: 'asc' }
|
265
268
|
)
|
266
269
|
}
|
267
270
|
it {
|
@@ -278,8 +281,8 @@ module Ransack
|
|
278
281
|
.sort_link(
|
279
282
|
[:main_app, Person.search()],
|
280
283
|
:name, [:name, 'email desc'],
|
281
|
-
:
|
282
|
-
:
|
284
|
+
controller: 'people',
|
285
|
+
default_order: { name: 'desc', email: 'asc' }
|
283
286
|
)
|
284
287
|
}
|
285
288
|
it {
|
@@ -295,7 +298,8 @@ module Ransack
|
|
295
298
|
subject { @controller.view_context
|
296
299
|
.sort_link(
|
297
300
|
[:main_app, Note.search()],
|
298
|
-
:notable_of_Person_type_name, "Notable",
|
301
|
+
:notable_of_Person_type_name, "Notable",
|
302
|
+
controller: 'notes'
|
299
303
|
)
|
300
304
|
}
|
301
305
|
it {
|
@@ -313,16 +317,17 @@ module Ransack
|
|
313
317
|
|
314
318
|
context 'view has existing parameters' do
|
315
319
|
before do
|
316
|
-
@controller.view_context.params.merge!({ :
|
320
|
+
@controller.view_context.params.merge!({ exist: 'existing' })
|
317
321
|
end
|
318
322
|
describe '#sort_link should not remove existing params' do
|
319
|
-
subject {
|
320
|
-
|
323
|
+
subject { @controller.view_context
|
324
|
+
.sort_link(
|
321
325
|
Person.search(
|
322
|
-
{ :
|
323
|
-
|
326
|
+
{ sorts: ['name desc'] },
|
327
|
+
search_key: 'people_search'
|
328
|
+
),
|
324
329
|
:name,
|
325
|
-
:
|
330
|
+
controller: 'people'
|
326
331
|
)
|
327
332
|
}
|
328
333
|
it { should match /exist\=existing/ }
|
@@ -332,10 +337,10 @@ module Ransack
|
|
332
337
|
describe '#sort_link with hide order indicator set to true' do
|
333
338
|
subject { @controller.view_context
|
334
339
|
.sort_link(
|
335
|
-
[:main_app, Person.search(:
|
340
|
+
[:main_app, Person.search(sorts: ['name desc'])],
|
336
341
|
:name,
|
337
|
-
:
|
338
|
-
:
|
342
|
+
controller: 'people',
|
343
|
+
hide_indicator: true
|
339
344
|
)
|
340
345
|
}
|
341
346
|
it { should match /Full Name/ }
|
@@ -344,24 +349,25 @@ module Ransack
|
|
344
349
|
describe '#sort_link with hide order indicator set to false' do
|
345
350
|
subject { @controller.view_context
|
346
351
|
.sort_link(
|
347
|
-
[:main_app, Person.search(:
|
352
|
+
[:main_app, Person.search(sorts: ['name desc'])],
|
348
353
|
:name,
|
349
|
-
:
|
350
|
-
:
|
354
|
+
controller: 'people',
|
355
|
+
hide_indicator: false
|
351
356
|
)
|
352
357
|
}
|
353
358
|
it { should match /Full Name ▼/ }
|
354
359
|
end
|
355
360
|
|
356
361
|
describe '#search_form_for with default format' do
|
357
|
-
subject { @controller.view_context
|
362
|
+
subject { @controller.view_context
|
363
|
+
.search_form_for(Person.search) {} }
|
358
364
|
it { should match /action="\/people"/ }
|
359
365
|
end
|
360
366
|
|
361
367
|
describe '#search_form_for with pdf format' do
|
362
368
|
subject {
|
363
369
|
@controller.view_context
|
364
|
-
.search_form_for(Person.search, :
|
370
|
+
.search_form_for(Person.search, format: :pdf) {}
|
365
371
|
}
|
366
372
|
it { should match /action="\/people.pdf"/ }
|
367
373
|
end
|
@@ -369,14 +375,15 @@ module Ransack
|
|
369
375
|
describe '#search_form_for with json format' do
|
370
376
|
subject {
|
371
377
|
@controller.view_context
|
372
|
-
.search_form_for(Person.search, :
|
378
|
+
.search_form_for(Person.search, format: :json) {}
|
373
379
|
}
|
374
380
|
it { should match /action="\/people.json"/ }
|
375
381
|
end
|
376
382
|
|
377
383
|
describe '#search_form_for with an array of routes' do
|
378
384
|
subject {
|
379
|
-
@controller.view_context
|
385
|
+
@controller.view_context
|
386
|
+
.search_form_for([:admin, Comment.search]) {}
|
380
387
|
}
|
381
388
|
it { should match /action="\/admin\/comments"/ }
|
382
389
|
end
|
data/spec/ransack/search_spec.rb
CHANGED
@@ -3,38 +3,38 @@ require 'spec_helper'
|
|
3
3
|
module Ransack
|
4
4
|
describe Search do
|
5
5
|
describe '#initialize' do
|
6
|
-
it
|
6
|
+
it 'removes empty conditions before building' do
|
7
7
|
expect_any_instance_of(Search).to receive(:build).with({})
|
8
|
-
Search.new(Person, :
|
8
|
+
Search.new(Person, name_eq: '')
|
9
9
|
end
|
10
10
|
|
11
|
-
it
|
11
|
+
it 'keeps conditions with a false value before building' do
|
12
12
|
expect_any_instance_of(Search).to receive(:build)
|
13
|
-
.with({
|
14
|
-
Search.new(Person, :
|
13
|
+
.with({ 'name_eq' => false })
|
14
|
+
Search.new(Person, name_eq: false)
|
15
15
|
end
|
16
16
|
|
17
|
-
it
|
17
|
+
it 'keeps conditions with a value before building' do
|
18
18
|
expect_any_instance_of(Search).to receive(:build)
|
19
|
-
.with({
|
20
|
-
Search.new(Person, :
|
19
|
+
.with({ 'name_eq' => 'foobar' })
|
20
|
+
Search.new(Person, name_eq: 'foobar')
|
21
21
|
end
|
22
22
|
|
23
|
-
it
|
23
|
+
it 'removes empty suffixed conditions before building' do
|
24
24
|
expect_any_instance_of(Search).to receive(:build).with({})
|
25
|
-
Search.new(Person, :
|
25
|
+
Search.new(Person, name_eq_any: [''])
|
26
26
|
end
|
27
27
|
|
28
|
-
it
|
28
|
+
it 'keeps suffixed conditions with a false value before building' do
|
29
29
|
expect_any_instance_of(Search).to receive(:build)
|
30
|
-
.with({
|
31
|
-
Search.new(Person, :
|
30
|
+
.with({ 'name_eq_any' => [false] })
|
31
|
+
Search.new(Person, name_eq_any: [false])
|
32
32
|
end
|
33
33
|
|
34
|
-
it
|
34
|
+
it 'keeps suffixed conditions with a value before building' do
|
35
35
|
expect_any_instance_of(Search).to receive(:build)
|
36
|
-
.with({
|
37
|
-
Search.new(Person, :
|
36
|
+
.with({ 'name_eq_any' => ['foobar'] })
|
37
|
+
Search.new(Person, name_eq_any: ['foobar'])
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'does not raise exception for string :params argument' do
|
@@ -43,19 +43,15 @@ module Ransack
|
|
43
43
|
|
44
44
|
it 'accepts a context option' do
|
45
45
|
shared_context = Context.for(Person)
|
46
|
-
search1 = Search.new(
|
47
|
-
|
48
|
-
)
|
49
|
-
search2 = Search.new(
|
50
|
-
Person, { "name_eq" => "B" }, context: shared_context
|
51
|
-
)
|
46
|
+
search1 = Search.new(Person, { name_eq: 'A' }, context: shared_context)
|
47
|
+
search2 = Search.new(Person, { name_eq: 'B' }, context: shared_context)
|
52
48
|
expect(search1.context).to be search2.context
|
53
49
|
end
|
54
50
|
end
|
55
51
|
|
56
52
|
describe '#build' do
|
57
53
|
it 'creates conditions for top-level attributes' do
|
58
|
-
search = Search.new(Person, :
|
54
|
+
search = Search.new(Person, name_eq: 'Ernie')
|
59
55
|
condition = search.base[:name_eq]
|
60
56
|
expect(condition).to be_a Nodes::Condition
|
61
57
|
expect(condition.predicate.name).to eq 'eq'
|
@@ -64,7 +60,7 @@ module Ransack
|
|
64
60
|
end
|
65
61
|
|
66
62
|
it 'creates conditions for association attributes' do
|
67
|
-
search = Search.new(Person, :
|
63
|
+
search = Search.new(Person, children_name_eq: 'Ernie')
|
68
64
|
condition = search.base[:children_name_eq]
|
69
65
|
expect(condition).to be_a Nodes::Condition
|
70
66
|
expect(condition.predicate.name).to eq 'eq'
|
@@ -73,33 +69,37 @@ module Ransack
|
|
73
69
|
end
|
74
70
|
|
75
71
|
it 'creates conditions for polymorphic belongs_to association attributes' do
|
76
|
-
search = Search.new(Note, :
|
72
|
+
search = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie')
|
77
73
|
condition = search.base[:notable_of_Person_type_name_eq]
|
78
74
|
expect(condition).to be_a Nodes::Condition
|
79
75
|
expect(condition.predicate.name).to eq 'eq'
|
80
|
-
expect(condition.attributes.first.name)
|
76
|
+
expect(condition.attributes.first.name)
|
77
|
+
.to eq 'notable_of_Person_type_name'
|
81
78
|
expect(condition.value).to eq 'Ernie'
|
82
79
|
end
|
83
80
|
|
84
|
-
it 'creates conditions for multiple polymorphic belongs_to association
|
81
|
+
it 'creates conditions for multiple polymorphic belongs_to association
|
82
|
+
attributes' do
|
85
83
|
search = Search.new(Note,
|
86
|
-
:
|
84
|
+
notable_of_Person_type_name_or_notable_of_Article_type_title_eq: 'Ernie')
|
87
85
|
condition = search.
|
88
86
|
base[:notable_of_Person_type_name_or_notable_of_Article_type_title_eq]
|
89
87
|
expect(condition).to be_a Nodes::Condition
|
90
88
|
expect(condition.predicate.name).to eq 'eq'
|
91
|
-
expect(condition.attributes.first.name)
|
92
|
-
|
89
|
+
expect(condition.attributes.first.name)
|
90
|
+
.to eq 'notable_of_Person_type_name'
|
91
|
+
expect(condition.attributes.last.name)
|
92
|
+
.to eq 'notable_of_Article_type_title'
|
93
93
|
expect(condition.value).to eq 'Ernie'
|
94
94
|
end
|
95
95
|
|
96
96
|
it 'preserves default scope conditions for associations' do
|
97
|
-
search = Search.new(Person, :
|
98
|
-
expect(search.result.to_sql).to include
|
97
|
+
search = Search.new(Person, articles_title_eq: 'Test')
|
98
|
+
expect(search.result.to_sql).to include 'default_scope'
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'discards empty conditions' do
|
102
|
-
search = Search.new(Person, :
|
102
|
+
search = Search.new(Person, children_name_eq: '')
|
103
103
|
condition = search.base[:children_name_eq]
|
104
104
|
expect(condition).to be_nil
|
105
105
|
end
|
@@ -112,8 +112,8 @@ module Ransack
|
|
112
112
|
it 'accepts arrays of groupings' do
|
113
113
|
search = Search.new(Person,
|
114
114
|
g: [
|
115
|
-
{ :
|
116
|
-
{ :
|
115
|
+
{ m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' },
|
116
|
+
{ m: 'or', name_eq: 'Bert', children_name_eq: 'Bert' },
|
117
117
|
]
|
118
118
|
)
|
119
119
|
ors = search.groupings
|
@@ -143,11 +143,13 @@ module Ransack
|
|
143
143
|
|
144
144
|
it 'accepts "attributes" hashes for conditions' do
|
145
145
|
search = Search.new(Person,
|
146
|
-
:
|
147
|
-
'0' => { :
|
148
|
-
'1' => {
|
149
|
-
:
|
150
|
-
|
146
|
+
c: {
|
147
|
+
'0' => { a: ['name'], p: 'eq', v: ['Ernie'] },
|
148
|
+
'1' => {
|
149
|
+
a: ['children_name', 'parent_name'],
|
150
|
+
p: 'eq', v: ['Ernie'], m: 'or'
|
151
|
+
}
|
152
|
+
}
|
151
153
|
)
|
152
154
|
conditions = search.base.conditions
|
153
155
|
expect(conditions.size).to eq(2)
|
@@ -157,10 +159,10 @@ module Ransack
|
|
157
159
|
|
158
160
|
it 'creates conditions for custom predicates that take arrays' do
|
159
161
|
Ransack.configure do |config|
|
160
|
-
config.add_predicate 'ary_pred', :
|
162
|
+
config.add_predicate 'ary_pred', wants_array: true
|
161
163
|
end
|
162
164
|
|
163
|
-
search = Search.new(Person, :
|
165
|
+
search = Search.new(Person, name_ary_pred: ['Ernie', 'Bert'])
|
164
166
|
condition = search.base[:name_ary_pred]
|
165
167
|
expect(condition).to be_a Nodes::Condition
|
166
168
|
expect(condition.predicate.name).to eq 'ary_pred'
|
@@ -169,14 +171,14 @@ module Ransack
|
|
169
171
|
end
|
170
172
|
|
171
173
|
it 'does not evaluate the query on #inspect' do
|
172
|
-
search = Search.new(Person, :
|
174
|
+
search = Search.new(Person, children_id_in: [1, 2, 3])
|
173
175
|
expect(search.inspect).not_to match /ActiveRecord/
|
174
176
|
end
|
175
177
|
|
176
178
|
context 'with an invalid condition' do
|
177
|
-
subject { Search.new(Person, :
|
179
|
+
subject { Search.new(Person, unknown_attr_eq: 'Ernie') }
|
178
180
|
|
179
|
-
context
|
181
|
+
context 'when ignore_unknown_conditions is false' do
|
180
182
|
before do
|
181
183
|
Ransack.configure { |c| c.ignore_unknown_conditions = false }
|
182
184
|
end
|
@@ -184,7 +186,7 @@ module Ransack
|
|
184
186
|
specify { expect { subject }.to raise_error ArgumentError }
|
185
187
|
end
|
186
188
|
|
187
|
-
context
|
189
|
+
context 'when ignore_unknown_conditions is true' do
|
188
190
|
before do
|
189
191
|
Ransack.configure { |c| c.ignore_unknown_conditions = true }
|
190
192
|
end
|
@@ -194,7 +196,7 @@ module Ransack
|
|
194
196
|
end
|
195
197
|
|
196
198
|
it 'does not modify the parameters' do
|
197
|
-
params = { :
|
199
|
+
params = { name_eq: '' }
|
198
200
|
expect { Search.new(Person, params) }.not_to change { params }
|
199
201
|
end
|
200
202
|
|
@@ -208,68 +210,87 @@ module Ransack
|
|
208
210
|
"#{quote_table_name("children_people")}.#{quote_column_name("name")}"
|
209
211
|
}
|
210
212
|
it 'evaluates conditions contextually' do
|
211
|
-
search = Search.new(Person, :
|
213
|
+
search = Search.new(Person, children_name_eq: 'Ernie')
|
212
214
|
expect(search.result).to be_an ActiveRecord::Relation
|
213
|
-
|
214
|
-
|
215
|
+
expect(search.result.to_sql).to match /#{
|
216
|
+
children_people_name_field} = 'Ernie'/
|
217
|
+
end
|
218
|
+
|
219
|
+
# FIXME: Make this spec pass for Rails 4.1 / 4.2 / 5.0 and not just 4.0 by
|
220
|
+
# commenting out lines 221 and 242 to run the test. Addresses issue #374.
|
221
|
+
# https://github.com/activerecord-hackery/ransack/issues/374
|
222
|
+
#
|
223
|
+
if ::ActiveRecord::VERSION::STRING.first(3) == '4.0'
|
224
|
+
it 'evaluates conditions for multiple belongs_to associations to the
|
225
|
+
same table contextually' do
|
226
|
+
s = Search.new(Recommendation,
|
227
|
+
person_name_eq: 'Ernie',
|
228
|
+
target_person_parent_name_eq: 'Test'
|
229
|
+
).result
|
230
|
+
expect(s).to be_an ActiveRecord::Relation
|
231
|
+
real_query = remove_quotes_and_backticks(s.to_sql)
|
232
|
+
expected_query = <<-SQL
|
233
|
+
SELECT recommendations.* FROM recommendations
|
234
|
+
LEFT OUTER JOIN people ON people.id = recommendations.person_id
|
235
|
+
LEFT OUTER JOIN people target_people_recommendations
|
236
|
+
ON target_people_recommendations.id = recommendations.target_person_id
|
237
|
+
LEFT OUTER JOIN people parents_people
|
238
|
+
ON parents_people.id = target_people_recommendations.parent_id
|
239
|
+
WHERE ((people.name = 'Ernie' AND parents_people.name = 'Test'))
|
240
|
+
SQL
|
241
|
+
.squish
|
242
|
+
expect(real_query).to eq expected_query
|
243
|
+
end
|
215
244
|
end
|
216
245
|
|
217
246
|
it 'evaluates compound conditions contextually' do
|
218
|
-
search = Search.new(Person, :
|
219
|
-
expect(search
|
220
|
-
|
221
|
-
expect(where.to_sql).to match /#{children_people_name_field
|
247
|
+
search = Search.new(Person, children_name_or_name_eq: 'Ernie').result
|
248
|
+
expect(search).to be_an ActiveRecord::Relation
|
249
|
+
expect(search.to_sql).to match /#{children_people_name_field
|
222
250
|
} = 'Ernie' OR #{people_name_field} = 'Ernie'/
|
223
251
|
end
|
224
252
|
|
225
253
|
it 'evaluates polymorphic belongs_to association conditions contextually' do
|
226
|
-
search = Search.new(Note, :
|
227
|
-
|
228
|
-
|
229
|
-
expect(
|
254
|
+
search = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie')
|
255
|
+
.result
|
256
|
+
expect(search).to be_an ActiveRecord::Relation
|
257
|
+
expect(search.to_sql).to match /#{people_name_field} = 'Ernie'/
|
230
258
|
end
|
231
259
|
|
232
260
|
it 'evaluates nested conditions' do
|
233
|
-
search = Search.new(Person, :
|
234
|
-
:
|
235
|
-
{ :
|
236
|
-
:name_eq => 'Ernie',
|
237
|
-
:children_children_name_eq => 'Ernie'
|
238
|
-
}
|
261
|
+
search = Search.new(Person, children_name_eq: 'Ernie',
|
262
|
+
g: [
|
263
|
+
{ m: 'or', name_eq: 'Ernie', children_children_name_eq: 'Ernie' }
|
239
264
|
]
|
240
|
-
)
|
241
|
-
expect(search
|
242
|
-
|
243
|
-
expect(
|
244
|
-
expect(
|
245
|
-
|
246
|
-
|
265
|
+
).result
|
266
|
+
expect(search).to be_an ActiveRecord::Relation
|
267
|
+
first, last = search.to_sql.split(/ AND /)
|
268
|
+
expect(first).to match /#{children_people_name_field} = 'Ernie'/
|
269
|
+
expect(last).to match /#{
|
270
|
+
people_name_field} = 'Ernie' OR #{
|
271
|
+
quote_table_name("children_people_2")}.#{
|
272
|
+
quote_column_name("name")} = 'Ernie'/
|
247
273
|
end
|
248
274
|
|
249
275
|
it 'evaluates arrays of groupings' do
|
250
276
|
search = Search.new(Person,
|
251
|
-
:
|
252
|
-
{ :
|
253
|
-
{ :
|
277
|
+
g: [
|
278
|
+
{ m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' },
|
279
|
+
{ m: 'or', name_eq: 'Bert', children_name_eq: 'Bert' }
|
254
280
|
]
|
255
|
-
)
|
256
|
-
expect(search
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
expect(
|
261
|
-
|
262
|
-
expect(second).to match /#{people_name_field} = 'Bert'/
|
263
|
-
expect(second).to match /#{children_people_name_field} = 'Bert'/
|
281
|
+
).result
|
282
|
+
expect(search).to be_an ActiveRecord::Relation
|
283
|
+
first, last = search.to_sql.split(/ AND /)
|
284
|
+
expect(first).to match /#{people_name_field} = 'Ernie' OR #{
|
285
|
+
children_people_name_field} = 'Ernie'/
|
286
|
+
expect(last).to match /#{people_name_field} = 'Bert' OR #{
|
287
|
+
children_people_name_field} = 'Bert'/
|
264
288
|
end
|
265
289
|
|
266
|
-
it 'returns distinct records when passed :
|
267
|
-
search = Search.new(
|
268
|
-
|
269
|
-
{ :
|
270
|
-
:comments_body_cont => 'e',
|
271
|
-
:articles_comments_body_cont => 'e'
|
272
|
-
}
|
290
|
+
it 'returns distinct records when passed distinct: true' do
|
291
|
+
search = Search.new(Person,
|
292
|
+
g: [
|
293
|
+
{ m: 'or', comments_body_cont: 'e', articles_comments_body_cont: 'e' }
|
273
294
|
]
|
274
295
|
)
|
275
296
|
if ActiveRecord::VERSION::MAJOR == 3
|
@@ -279,11 +300,17 @@ module Ransack
|
|
279
300
|
end
|
280
301
|
expect(search.result.send(all_or_load).size)
|
281
302
|
.to eq(9000)
|
282
|
-
expect(search.result(:
|
303
|
+
expect(search.result(distinct: true).size)
|
283
304
|
.to eq(10)
|
284
305
|
expect(search.result.send(all_or_load).send(uniq_or_distinct))
|
285
|
-
.to eq search.result(:
|
306
|
+
.to eq search.result(distinct: true).send(all_or_load)
|
286
307
|
end
|
308
|
+
|
309
|
+
private
|
310
|
+
|
311
|
+
def remove_quotes_and_backticks(str)
|
312
|
+
str.gsub(/["`]/, '')
|
313
|
+
end
|
287
314
|
end
|
288
315
|
|
289
316
|
describe '#sorts=' do
|
@@ -319,7 +346,7 @@ module Ransack
|
|
319
346
|
end
|
320
347
|
|
321
348
|
it 'creates sorts based on multiple attributes/directions in array format' do
|
322
|
-
@s.sorts = ['id desc', { :
|
349
|
+
@s.sorts = ['id desc', { name: 'name', dir: 'asc' }]
|
323
350
|
expect(@s.sorts.size).to eq(2)
|
324
351
|
sort1, sort2 = @s.sorts
|
325
352
|
expect(sort1).to be_a Nodes::Sort
|
@@ -331,7 +358,7 @@ module Ransack
|
|
331
358
|
end
|
332
359
|
|
333
360
|
it 'creates sorts based on multiple attributes and uppercase directions in array format' do
|
334
|
-
@s.sorts = ['id DESC', { :
|
361
|
+
@s.sorts = ['id DESC', { name: 'name', dir: 'ASC' }]
|
335
362
|
expect(@s.sorts.size).to eq(2)
|
336
363
|
sort1, sort2 = @s.sorts
|
337
364
|
expect(sort1).to be_a Nodes::Sort
|
@@ -342,7 +369,8 @@ module Ransack
|
|
342
369
|
expect(sort2.dir).to eq 'asc'
|
343
370
|
end
|
344
371
|
|
345
|
-
it 'creates sorts based on multiple attributes and different directions
|
372
|
+
it 'creates sorts based on multiple attributes and different directions
|
373
|
+
in array format' do
|
346
374
|
@s.sorts = ['id DESC', { name: 'name', dir: nil }]
|
347
375
|
expect(@s.sorts.size).to eq(2)
|
348
376
|
sort1, sort2 = @s.sorts
|
@@ -356,8 +384,8 @@ module Ransack
|
|
356
384
|
|
357
385
|
it 'creates sorts based on multiple attributes/directions in hash format' do
|
358
386
|
@s.sorts = {
|
359
|
-
'0' => { :
|
360
|
-
'1' => { :
|
387
|
+
'0' => { name: 'id', dir: 'desc' },
|
388
|
+
'1' => { name: 'name', dir: 'asc' }
|
361
389
|
}
|
362
390
|
expect(@s.sorts.size).to eq(2)
|
363
391
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
@@ -367,10 +395,11 @@ module Ransack
|
|
367
395
|
expect(name_sort.dir).to eq 'asc'
|
368
396
|
end
|
369
397
|
|
370
|
-
it 'creates sorts based on multiple attributes and uppercase directions
|
398
|
+
it 'creates sorts based on multiple attributes and uppercase directions
|
399
|
+
in hash format' do
|
371
400
|
@s.sorts = {
|
372
|
-
'0' => { :
|
373
|
-
'1' => { :
|
401
|
+
'0' => { name: 'id', dir: 'DESC' },
|
402
|
+
'1' => { name: 'name', dir: 'ASC' }
|
374
403
|
}
|
375
404
|
expect(@s.sorts.size).to eq(2)
|
376
405
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
@@ -380,10 +409,11 @@ module Ransack
|
|
380
409
|
expect(name_sort.dir).to eq 'asc'
|
381
410
|
end
|
382
411
|
|
383
|
-
it 'creates sorts based on multiple attributes and different directions
|
412
|
+
it 'creates sorts based on multiple attributes and different directions
|
413
|
+
in hash format' do
|
384
414
|
@s.sorts = {
|
385
|
-
'0' => { :
|
386
|
-
'1' => { :
|
415
|
+
'0' => { name: 'id', dir: 'DESC' },
|
416
|
+
'1' => { name: 'name', dir: nil }
|
387
417
|
}
|
388
418
|
expect(@s.sorts.size).to eq(2)
|
389
419
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
@@ -415,7 +445,7 @@ module Ransack
|
|
415
445
|
|
416
446
|
it 'allows chaining to access nested conditions' do
|
417
447
|
@s.groupings = [
|
418
|
-
{ :
|
448
|
+
{ m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' }
|
419
449
|
]
|
420
450
|
expect(@s.groupings.first.children_name_eq).to eq 'Ernie'
|
421
451
|
end
|