ransack 0.7.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.travis.yml +10 -3
- data/CONTRIBUTING.md +1 -2
- data/Gemfile +3 -3
- data/README.md +78 -57
- data/lib/ransack/adapters/active_record.rb +2 -0
- data/lib/ransack/adapters/active_record/3.0/context.rb +9 -15
- data/lib/ransack/adapters/active_record/3.1/context.rb +9 -14
- data/lib/ransack/adapters/active_record/3.2/context.rb +44 -0
- data/lib/ransack/adapters/active_record/context.rb +11 -9
- data/lib/ransack/constants.rb +6 -1
- data/lib/ransack/context.rb +15 -1
- data/lib/ransack/helpers/form_builder.rb +2 -1
- data/lib/ransack/helpers/form_helper.rb +3 -2
- data/lib/ransack/locale/es.yml +1 -1
- data/lib/ransack/locale/fr.yml +70 -0
- data/lib/ransack/translate.rb +9 -8
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +3 -3
- data/spec/ransack/adapters/active_record/context_spec.rb +6 -0
- data/spec/ransack/helpers/form_builder_spec.rb +16 -6
- data/spec/ransack/helpers/form_helper_spec.rb +57 -10
- data/spec/ransack/predicate_spec.rb +37 -4
- data/spec/ransack/search_spec.rb +50 -35
- data/spec/spec_helper.rb +2 -0
- data/spec/support/en.yml +3 -1
- data/spec/support/schema.rb +40 -35
- metadata +16 -29
data/lib/ransack/constants.rb
CHANGED
@@ -23,7 +23,12 @@ module Ransack
|
|
23
23
|
module_function
|
24
24
|
# replace % \ to \% \\
|
25
25
|
def escape_wildcards(unescaped)
|
26
|
-
|
26
|
+
if ActiveRecord::VERSION::MAJOR == 3
|
27
|
+
unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1')
|
28
|
+
else
|
29
|
+
unescaped.to_s.gsub(/\\/){ "\\\\" }.gsub(/%/, "\\%")
|
30
|
+
end
|
27
31
|
end
|
32
|
+
|
28
33
|
end
|
29
34
|
end
|
data/lib/ransack/context.rb
CHANGED
@@ -28,7 +28,7 @@ module Ransack
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def initialize(object, options = {})
|
31
|
-
@object = object
|
31
|
+
@object = relation_for(object)
|
32
32
|
@klass = @object.klass
|
33
33
|
@join_dependency = join_dependency(@object)
|
34
34
|
@join_type = options[:join_type] || Arel::OuterJoin
|
@@ -44,6 +44,20 @@ module Ransack
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
def klassify(obj)
|
48
|
+
if Class === obj && ::ActiveRecord::Base > obj
|
49
|
+
obj
|
50
|
+
elsif obj.respond_to? :klass
|
51
|
+
obj.klass
|
52
|
+
elsif obj.respond_to? :active_record # Rails 3
|
53
|
+
obj.active_record
|
54
|
+
elsif obj.respond_to? :base_klass # Rails 4
|
55
|
+
obj.base_klass
|
56
|
+
else
|
57
|
+
raise ArgumentError, "Don't know how to klassify #{obj}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
47
61
|
# Convert a string representing a chain of associations and an attribute
|
48
62
|
# into the attribute itself
|
49
63
|
def contextualize(str)
|
@@ -59,11 +59,12 @@ module Ransack
|
|
59
59
|
query_hash = {}
|
60
60
|
query_hash[search.context.search_key] = search_params.merge(:s => "#{attr_name} #{new_dir}")
|
61
61
|
options.merge!(query_hash)
|
62
|
+
options_for_url = params.merge options
|
62
63
|
|
63
64
|
url = if routing_proxy && respond_to?(routing_proxy)
|
64
|
-
send(routing_proxy).url_for(
|
65
|
+
send(routing_proxy).url_for(options_for_url)
|
65
66
|
else
|
66
|
-
url_for(
|
67
|
+
url_for(options_for_url)
|
67
68
|
end
|
68
69
|
|
69
70
|
link_to [ERB::Util.h(name), order_indicator_for(current_dir)].compact.join(' ').html_safe,
|
data/lib/ransack/locale/es.yml
CHANGED
@@ -0,0 +1,70 @@
|
|
1
|
+
fr:
|
2
|
+
ransack:
|
3
|
+
search: "recherche"
|
4
|
+
predicate: "prédicat"
|
5
|
+
and: "et"
|
6
|
+
or: "ou"
|
7
|
+
any: "au moins un"
|
8
|
+
all: "tous"
|
9
|
+
combinator: "combinateur"
|
10
|
+
attribute: "attribut"
|
11
|
+
value: "valeur"
|
12
|
+
condition: "condition"
|
13
|
+
sort: "tri"
|
14
|
+
asc: "ascendant"
|
15
|
+
desc: "descendant"
|
16
|
+
predicates:
|
17
|
+
eq: "égal à"
|
18
|
+
eq_any: "égal à au moins un"
|
19
|
+
eq_all: "égal à tous"
|
20
|
+
not_eq: "différent de"
|
21
|
+
not_eq_any: "différent d'au moins un"
|
22
|
+
not_eq_all: "différent de tous"
|
23
|
+
matches: "correspond à"
|
24
|
+
matches_any: "correspond à au moins un"
|
25
|
+
matches_all: "correspond à tous"
|
26
|
+
does_not_match: "ne correspond pas à"
|
27
|
+
does_not_match_any: "ne correspond pas à au moins un"
|
28
|
+
does_not_match_all: "ne correspond à aucun"
|
29
|
+
lt: "inférieur à"
|
30
|
+
lt_any: "inférieur à au moins un"
|
31
|
+
lt_all: "inférieur à tous"
|
32
|
+
lteq: "inférieur ou égal à"
|
33
|
+
lteq_any: "inférieur ou égal à au moins un"
|
34
|
+
lteq_all: "inférieur ou égal à tous"
|
35
|
+
gt: "supérieur à"
|
36
|
+
gt_any: "supérieur à au moins un"
|
37
|
+
gt_all: "supérieur à tous"
|
38
|
+
gteq: "supérieur ou égal à"
|
39
|
+
gteq_any: "supérieur ou égal à au moins un"
|
40
|
+
gteq_all: "supérieur ou égal à tous"
|
41
|
+
in: "inclus dans"
|
42
|
+
in_any: "inclus dans au moins un"
|
43
|
+
in_all: "inclus dans tous"
|
44
|
+
not_in: "non inclus dans"
|
45
|
+
not_in_any: "non inclus dans au moins un"
|
46
|
+
not_in_all: "non inclus dans tous"
|
47
|
+
cont: "contient"
|
48
|
+
cont_any: "contient au moins un"
|
49
|
+
cont_all: "contient tous"
|
50
|
+
not_cont: "ne contient pas"
|
51
|
+
not_cont_any: "ne contient pas au moins un"
|
52
|
+
not_cont_all: "ne contient pas tous"
|
53
|
+
start: "commence par"
|
54
|
+
start_any: "commence par au moins un"
|
55
|
+
start_all: "commence par tous"
|
56
|
+
not_start: "ne commence pas par"
|
57
|
+
not_start_any: "ne commence pas par au moins un"
|
58
|
+
not_start_all: "ne commence pas par tous"
|
59
|
+
end: "finit par"
|
60
|
+
end_any: "finit par au moins un"
|
61
|
+
end_all: "finit par tous"
|
62
|
+
not_end: "ne finit pas par"
|
63
|
+
not_end_any: "ne finit pas par au moins un"
|
64
|
+
not_end_all: "ne finit pas par tous"
|
65
|
+
'true': "est vrai"
|
66
|
+
'false': "est faux"
|
67
|
+
present: "est présent"
|
68
|
+
blank: "est blanc"
|
69
|
+
'null': "est null"
|
70
|
+
not_null: "n'est pas null"
|
data/lib/ransack/translate.rb
CHANGED
@@ -23,7 +23,7 @@ module Ransack
|
|
23
23
|
attribute_names = attributes_str.split(/_and_|_or_/)
|
24
24
|
combinator = attributes_str.match(/_and_/) ? :and : :or
|
25
25
|
defaults = base_ancestors.map do |klass|
|
26
|
-
:"ransack.attributes.#{klass.model_name.
|
26
|
+
:"ransack.attributes.#{klass.model_name.singular}.#{original_name}"
|
27
27
|
end
|
28
28
|
|
29
29
|
translated_names = attribute_names.map do |attr|
|
@@ -50,7 +50,7 @@ module Ransack
|
|
50
50
|
raise ArgumentError, "A context is required to translate associations"
|
51
51
|
end
|
52
52
|
|
53
|
-
defaults = key.blank? ? [:"#{context.klass.i18n_scope}.models.#{context.klass.model_name.
|
53
|
+
defaults = key.blank? ? [:"#{context.klass.i18n_scope}.models.#{context.klass.model_name.singular}"] : [:"ransack.associations.#{context.klass.model_name.singular}.#{key}"]
|
54
54
|
defaults << context.traverse(key).model_name.human
|
55
55
|
options = {:count => 1, :default => defaults}
|
56
56
|
I18n.translate(defaults.shift, options)
|
@@ -65,19 +65,20 @@ module Ransack
|
|
65
65
|
interpolations = {}
|
66
66
|
interpolations[:attr_fallback_name] = I18n.translate(
|
67
67
|
(associated_class ?
|
68
|
-
:"ransack.attributes.#{associated_class.model_name.
|
69
|
-
:"ransack.attributes.#{context.klass.model_name.
|
68
|
+
:"ransack.attributes.#{associated_class.model_name.singular}.#{attr_name}" :
|
69
|
+
:"ransack.attributes.#{context.klass.model_name.singular}.#{attr_name}"
|
70
70
|
),
|
71
71
|
:default => [
|
72
72
|
(associated_class ?
|
73
|
-
:"#{associated_class.i18n_scope}.attributes.#{associated_class.model_name.
|
74
|
-
:"#{context.klass.i18n_scope}.attributes.#{context.klass.model_name.
|
73
|
+
:"#{associated_class.i18n_scope}.attributes.#{associated_class.model_name.singular}.#{attr_name}" :
|
74
|
+
:"#{context.klass.i18n_scope}.attributes.#{context.klass.model_name.singular}.#{attr_name}"
|
75
75
|
),
|
76
|
+
:".attributes.#{attr_name}",
|
76
77
|
attr_name.humanize
|
77
78
|
]
|
78
79
|
)
|
79
80
|
defaults = [
|
80
|
-
:"ransack.attributes.#{context.klass.model_name.
|
81
|
+
:"ransack.attributes.#{context.klass.model_name.singular}.#{name}"
|
81
82
|
]
|
82
83
|
if include_associations && associated_class
|
83
84
|
defaults << '%{association_name} %{attr_fallback_name}'
|
@@ -89,4 +90,4 @@ module Ransack
|
|
89
90
|
I18n.translate(defaults.shift, options.merge(interpolations))
|
90
91
|
end
|
91
92
|
end
|
92
|
-
end
|
93
|
+
end
|
data/lib/ransack/version.rb
CHANGED
data/ransack.gemspec
CHANGED
@@ -14,9 +14,9 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
s.rubyforge_project = "ransack"
|
16
16
|
|
17
|
-
s.add_dependency 'activerecord', '
|
18
|
-
s.add_dependency 'actionpack', '
|
19
|
-
s.add_dependency 'polyamorous', '~> 0.
|
17
|
+
s.add_dependency 'activerecord', '>= 3.0'
|
18
|
+
s.add_dependency 'actionpack', '>= 3.0'
|
19
|
+
s.add_dependency 'polyamorous', '~> 0.6.0'
|
20
20
|
s.add_development_dependency 'rspec', '~> 2.8.0'
|
21
21
|
s.add_development_dependency 'machinist', '~> 1.0.6'
|
22
22
|
s.add_development_dependency 'faker', '~> 0.9.5'
|
@@ -6,6 +6,12 @@ module Ransack
|
|
6
6
|
describe Context do
|
7
7
|
subject { Context.new(Person) }
|
8
8
|
|
9
|
+
describe '#relation_for' do
|
10
|
+
it 'returns relation for given object' do
|
11
|
+
subject.object.should be_an ::ActiveRecord::Relation
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
9
15
|
describe '#evaluate' do
|
10
16
|
it 'evaluates search obects' do
|
11
17
|
search = Search.new(Person, :name_eq => 'Joe Blow')
|
@@ -7,7 +7,7 @@ module Ransack
|
|
7
7
|
router = ActionDispatch::Routing::RouteSet.new
|
8
8
|
router.draw do
|
9
9
|
resources :people
|
10
|
-
|
10
|
+
get ':controller(/:action(/:id(.:format)))'
|
11
11
|
end
|
12
12
|
|
13
13
|
include router.url_helpers
|
@@ -48,11 +48,21 @@ module Ransack
|
|
48
48
|
end
|
49
49
|
|
50
50
|
describe '#sort_link' do
|
51
|
-
|
51
|
+
it 'sort_link for ransack attribute' do
|
52
|
+
sort_link = @f.sort_link :name, :controller => 'people'
|
53
|
+
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
|
54
|
+
sort_link.should match /people\?q%5Bs%5D=name\+asc/
|
55
|
+
else
|
56
|
+
sort_link.should match /people\?q(%5B|\[)s(%5D|\])=name\+asc/
|
57
|
+
end
|
58
|
+
sort_link.should match /sort_link/
|
59
|
+
sort_link.should match /Full Name<\/a>/
|
60
|
+
end
|
52
61
|
|
53
|
-
it
|
54
|
-
|
55
|
-
|
62
|
+
it 'sort_link for common attribute' do
|
63
|
+
sort_link = @f.sort_link :id, :controller => 'people'
|
64
|
+
sort_link.should match /id<\/a>/
|
65
|
+
end
|
56
66
|
end
|
57
67
|
|
58
68
|
describe '#submit' do
|
@@ -124,4 +134,4 @@ module Ransack
|
|
124
134
|
end
|
125
135
|
end
|
126
136
|
end
|
127
|
-
end
|
137
|
+
end
|
@@ -7,7 +7,7 @@ module Ransack
|
|
7
7
|
router = ActionDispatch::Routing::RouteSet.new
|
8
8
|
router.draw do
|
9
9
|
resources :people
|
10
|
-
|
10
|
+
get ':controller(/:action(/:id(.:format)))'
|
11
11
|
end
|
12
12
|
|
13
13
|
include router.url_helpers
|
@@ -26,24 +26,71 @@ module Ransack
|
|
26
26
|
end
|
27
27
|
|
28
28
|
describe '#sort_link with default search_key' do
|
29
|
-
subject {
|
30
|
-
|
29
|
+
subject {
|
30
|
+
@controller.view_context.sort_link(
|
31
|
+
[:main_app, Person.search(:sorts => ['name desc'])],
|
32
|
+
:name, :controller => 'people'
|
33
|
+
)
|
34
|
+
}
|
35
|
+
it { should match(
|
36
|
+
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
|
37
|
+
/people\?q%5Bs%5D=name\+asc/
|
38
|
+
else
|
39
|
+
/people\?q(%5B|\[)s(%5D|\])=name\+asc/
|
40
|
+
end)
|
41
|
+
}
|
31
42
|
it { should match /sort_link desc/ }
|
32
43
|
it { should match /Full Name ▼/ }
|
33
44
|
end
|
34
45
|
|
35
46
|
describe '#sort_link with default search_key defined as symbol' do
|
36
|
-
subject { @controller.
|
37
|
-
|
38
|
-
|
39
|
-
|
47
|
+
subject { @controller.
|
48
|
+
view_context.sort_link(
|
49
|
+
Person.search({ :sorts => ['name desc'] }, :search_key => :people_search),
|
50
|
+
:name, :controller => 'people'
|
51
|
+
)
|
52
|
+
}
|
53
|
+
it { should match(
|
54
|
+
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
|
55
|
+
/people\?people_search%5Bs%5D=name\+asc/
|
56
|
+
else
|
57
|
+
/people\?people_search(%5B|\[)s(%5D|\])=name\+asc/
|
58
|
+
end)
|
59
|
+
}
|
40
60
|
end
|
41
61
|
|
42
62
|
describe '#sort_link with default search_key defined as string' do
|
43
|
-
subject {
|
44
|
-
|
63
|
+
subject {
|
64
|
+
@controller.view_context.sort_link(
|
65
|
+
Person.search({ :sorts => ['name desc'] }, :search_key => 'people_search'),
|
66
|
+
:name, :controller => 'people'
|
67
|
+
)
|
68
|
+
}
|
69
|
+
it { should match(
|
70
|
+
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
|
71
|
+
/people\?people_search%5Bs%5D=name\+asc/
|
72
|
+
else
|
73
|
+
/people\?people_search(%5B|\[)s(%5D|\])=name\+asc/
|
74
|
+
end)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
45
78
|
|
46
|
-
|
79
|
+
context 'view has existing parameters' do
|
80
|
+
before do
|
81
|
+
@controller.view_context.params.merge!({ :exist => 'existing' })
|
82
|
+
end
|
83
|
+
describe '#sort_link should not remove existing params' do
|
84
|
+
subject {
|
85
|
+
@controller.view_context.sort_link(
|
86
|
+
Person.search({ :sorts => ['name desc'] }, :search_key => 'people_search'),
|
87
|
+
:name, :controller => 'people'
|
88
|
+
)
|
89
|
+
}
|
90
|
+
it {
|
91
|
+
should match /exist\=existing/
|
92
|
+
}
|
93
|
+
end
|
47
94
|
end
|
48
95
|
end
|
49
96
|
end
|
@@ -7,6 +7,24 @@ module Ransack
|
|
7
7
|
@s = Search.new(Person)
|
8
8
|
end
|
9
9
|
|
10
|
+
shared_examples 'wildcard escaping' do |method, regexp|
|
11
|
+
it 'automatically converts integers to strings' do
|
12
|
+
subject.parent_id_cont = 1
|
13
|
+
expect { subject.result }.to_not raise_error
|
14
|
+
end
|
15
|
+
|
16
|
+
it (
|
17
|
+
if ActiveRecord::VERSION::MAJOR == 3
|
18
|
+
"escapes '%', '.' and '\\\\' in value"
|
19
|
+
else
|
20
|
+
"escapes % and \\ in value"
|
21
|
+
end
|
22
|
+
) do
|
23
|
+
subject.send(:"#{method}=", '%._\\')
|
24
|
+
subject.result.to_sql.should match(regexp)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
10
28
|
describe 'eq' do
|
11
29
|
it 'generates an equality condition for boolean true' do
|
12
30
|
@s.awesome_eq = true
|
@@ -25,17 +43,32 @@ module Ransack
|
|
25
43
|
end
|
26
44
|
|
27
45
|
describe 'cont' do
|
46
|
+
|
47
|
+
it_has_behavior 'wildcard escaping', :name_cont, (
|
48
|
+
if ActiveRecord::VERSION::MAJOR == 3
|
49
|
+
/"people"."name" LIKE '%\\%\\._\\\\%'/
|
50
|
+
else
|
51
|
+
/"people"."name" LIKE '%\\%._\\\\%'/
|
52
|
+
end) do
|
53
|
+
subject { @s }
|
54
|
+
end
|
55
|
+
|
28
56
|
it 'generates a LIKE query with value surrounded by %' do
|
29
57
|
@s.name_cont = 'ric'
|
30
58
|
@s.result.to_sql.should match /"people"."name" LIKE '%ric%'/
|
31
59
|
end
|
32
|
-
it 'escapes %, _ and \\ in value' do
|
33
|
-
@s.name_cont = '%_\\'
|
34
|
-
@s.result.to_sql.should match /"people"."name" LIKE '%\\%\\_\\\\%'/
|
35
|
-
end
|
36
60
|
end
|
37
61
|
|
38
62
|
describe 'not_cont' do
|
63
|
+
it_has_behavior 'wildcard escaping', :name_not_cont, (
|
64
|
+
if ActiveRecord::VERSION::MAJOR == 3
|
65
|
+
/"people"."name" NOT LIKE '%\\%\\._\\\\%'/
|
66
|
+
else
|
67
|
+
/"people"."name" NOT LIKE '%\\%._\\\\%'/
|
68
|
+
end) do
|
69
|
+
subject { @s }
|
70
|
+
end
|
71
|
+
|
39
72
|
it 'generates a NOT LIKE query with value surrounded by %' do
|
40
73
|
@s.name_not_cont = 'ric'
|
41
74
|
@s.result.to_sql.should match /"people"."name" NOT LIKE '%ric%'/
|
data/spec/ransack/search_spec.rb
CHANGED
@@ -32,8 +32,10 @@ module Ransack
|
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'creates Conditions for multiple polymorphic belongs_to association attributes' do
|
35
|
-
search = Search.new(Note,
|
36
|
-
|
35
|
+
search = Search.new(Note,
|
36
|
+
:notable_of_Person_type_name_or_notable_of_Article_type_title_eq => 'Ernie')
|
37
|
+
condition = search.
|
38
|
+
base[:notable_of_Person_type_name_or_notable_of_Article_type_title_eq]
|
37
39
|
condition.should be_a Nodes::Condition
|
38
40
|
condition.predicate.name.should eq 'eq'
|
39
41
|
condition.attributes.first.name.should eq 'notable_of_Person_type_name'
|
@@ -50,8 +52,8 @@ module Ransack
|
|
50
52
|
it 'accepts arrays of groupings' do
|
51
53
|
search = Search.new(Person,
|
52
54
|
:g => [
|
53
|
-
{:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
54
|
-
{:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'},
|
55
|
+
{ :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' },
|
56
|
+
{ :m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert' },
|
55
57
|
]
|
56
58
|
)
|
57
59
|
ors = search.groupings
|
@@ -66,8 +68,8 @@ module Ransack
|
|
66
68
|
it 'accepts "attributes" hashes for groupings' do
|
67
69
|
search = Search.new(Person,
|
68
70
|
:g => {
|
69
|
-
'0' => {:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
70
|
-
'1' => {:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'},
|
71
|
+
'0' => { :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' },
|
72
|
+
'1' => { :m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert' },
|
71
73
|
}
|
72
74
|
)
|
73
75
|
ors = search.groupings
|
@@ -82,8 +84,8 @@ module Ransack
|
|
82
84
|
it 'accepts "attributes" hashes for conditions' do
|
83
85
|
search = Search.new(Person,
|
84
86
|
:c => {
|
85
|
-
'0' => {:a => ['name'], :p => 'eq', :v => ['Ernie']},
|
86
|
-
'1' => {:a => ['children_name', 'parent_name'], :p => 'eq', :v => ['Ernie'], :m => 'or'}
|
87
|
+
'0' => { :a => ['name'], :p => 'eq', :v => ['Ernie'] },
|
88
|
+
'1' => { :a => ['children_name', 'parent_name'], :p => 'eq', :v => ['Ernie'], :m => 'or' }
|
87
89
|
}
|
88
90
|
)
|
89
91
|
conditions = search.base.conditions
|
@@ -93,8 +95,7 @@ module Ransack
|
|
93
95
|
|
94
96
|
it 'creates Conditions for custom predicates that take arrays' do
|
95
97
|
Ransack.configure do |config|
|
96
|
-
config.add_predicate 'ary_pred',
|
97
|
-
:wants_array => true
|
98
|
+
config.add_predicate 'ary_pred', :wants_array => true
|
98
99
|
end
|
99
100
|
|
100
101
|
search = Search.new(Person, :name_ary_pred => ['Ernie', 'Bert'])
|
@@ -135,11 +136,12 @@ module Ransack
|
|
135
136
|
|
136
137
|
it 'evaluates nested conditions' do
|
137
138
|
search = Search.new(Person, :children_name_eq => 'Ernie',
|
138
|
-
:g => [
|
139
|
-
:m => 'or',
|
140
|
-
|
141
|
-
|
142
|
-
|
139
|
+
:g => [
|
140
|
+
{ :m => 'or',
|
141
|
+
:name_eq => 'Ernie',
|
142
|
+
:children_children_name_eq => 'Ernie'
|
143
|
+
}
|
144
|
+
]
|
143
145
|
)
|
144
146
|
search.result.should be_an ActiveRecord::Relation
|
145
147
|
where = search.result.where_values.first
|
@@ -151,8 +153,8 @@ module Ransack
|
|
151
153
|
it 'evaluates arrays of groupings' do
|
152
154
|
search = Search.new(Person,
|
153
155
|
:g => [
|
154
|
-
{:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
155
|
-
{:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'},
|
156
|
+
{ :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' },
|
157
|
+
{ :m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert' },
|
156
158
|
]
|
157
159
|
)
|
158
160
|
search.result.should be_an ActiveRecord::Relation
|
@@ -166,10 +168,25 @@ module Ransack
|
|
166
168
|
end
|
167
169
|
|
168
170
|
it 'returns distinct records when passed :distinct => true' do
|
169
|
-
search = Search.new(
|
170
|
-
|
171
|
-
|
172
|
-
|
171
|
+
search = Search.new(
|
172
|
+
Person, :g => [
|
173
|
+
{ :m => 'or',
|
174
|
+
:comments_body_cont => 'e',
|
175
|
+
:articles_comments_body_cont => 'e'
|
176
|
+
}
|
177
|
+
]
|
178
|
+
)
|
179
|
+
if ActiveRecord::VERSION::MAJOR == 3
|
180
|
+
all_or_load, uniq_or_distinct = :all, :uniq
|
181
|
+
else
|
182
|
+
all_or_load, uniq_or_distinct = :load, :distinct
|
183
|
+
end
|
184
|
+
search.result.send(all_or_load).
|
185
|
+
should have(920).items
|
186
|
+
search.result(:distinct => true).
|
187
|
+
should have(330).items
|
188
|
+
search.result.send(all_or_load).send(uniq_or_distinct).
|
189
|
+
should eq search.result(:distinct => true).send(all_or_load)
|
173
190
|
end
|
174
191
|
end
|
175
192
|
|
@@ -201,22 +218,21 @@ module Ransack
|
|
201
218
|
|
202
219
|
it 'creates sorts based on multiple attributes/directions in hash format' do
|
203
220
|
@s.sorts = {
|
204
|
-
'0' => {
|
205
|
-
|
206
|
-
:dir => 'desc'
|
207
|
-
},
|
208
|
-
'1' => {
|
209
|
-
:name => 'name',
|
210
|
-
:dir => 'asc'
|
211
|
-
}
|
221
|
+
'0' => { :name => 'id', :dir => 'desc' },
|
222
|
+
'1' => { :name => 'name', :dir => 'asc' }
|
212
223
|
}
|
213
224
|
@s.sorts.should have(2).items
|
214
|
-
@s.sorts.should be_all {|s| Nodes::Sort === s}
|
215
|
-
id_sort = @s.sorts.detect {|s| s.name == 'id'}
|
216
|
-
name_sort = @s.sorts.detect {|s| s.name == 'name'}
|
225
|
+
@s.sorts.should be_all { |s| Nodes::Sort === s }
|
226
|
+
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
227
|
+
name_sort = @s.sorts.detect { |s| s.name == 'name' }
|
217
228
|
id_sort.dir.should eq 'desc'
|
218
229
|
name_sort.dir.should eq 'asc'
|
219
230
|
end
|
231
|
+
|
232
|
+
it 'overrides existing sort' do
|
233
|
+
@s.sorts = 'id asc'
|
234
|
+
@s.result.first.id.should eq 1
|
235
|
+
end
|
220
236
|
end
|
221
237
|
|
222
238
|
describe '#method_missing' do
|
@@ -225,7 +241,7 @@ module Ransack
|
|
225
241
|
end
|
226
242
|
|
227
243
|
it 'raises NoMethodError when sent an invalid attribute' do
|
228
|
-
expect {@s.blah}.to raise_error NoMethodError
|
244
|
+
expect { @s.blah }.to raise_error NoMethodError
|
229
245
|
end
|
230
246
|
|
231
247
|
it 'sets condition attributes when sent valid attributes' do
|
@@ -234,8 +250,7 @@ module Ransack
|
|
234
250
|
end
|
235
251
|
|
236
252
|
it 'allows chaining to access nested conditions' do
|
237
|
-
@s.groupings = [{:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'}]
|
238
|
-
@s.groupings.first.name_eq.should eq 'Ernie'
|
253
|
+
@s.groupings = [{ :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' }]
|
239
254
|
@s.groupings.first.children_name_eq.should eq 'Ernie'
|
240
255
|
end
|
241
256
|
end
|