ransack 1.2.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -4
- data/CONTRIBUTING.md +12 -4
- data/Gemfile +4 -5
- data/README.md +160 -55
- data/lib/ransack.rb +1 -1
- data/lib/ransack/adapters/active_record/3.0/context.rb +16 -0
- data/lib/ransack/adapters/active_record/3.1/context.rb +24 -0
- data/lib/ransack/adapters/active_record/base.rb +6 -0
- data/lib/ransack/adapters/active_record/context.rb +49 -1
- data/lib/ransack/configuration.rb +23 -6
- data/lib/ransack/constants.rb +46 -45
- data/lib/ransack/context.rb +19 -2
- data/lib/ransack/helpers/form_builder.rb +5 -4
- data/lib/ransack/helpers/form_helper.rb +34 -14
- data/lib/ransack/locale/hu.yml +70 -0
- data/lib/ransack/locale/nl.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +2 -2
- data/lib/ransack/nodes/condition.rb +29 -12
- data/lib/ransack/nodes/grouping.rb +6 -6
- data/lib/ransack/nodes/node.rb +1 -1
- data/lib/ransack/nodes/value.rb +1 -1
- data/lib/ransack/predicate.rb +4 -5
- data/lib/ransack/ransacker.rb +1 -1
- data/lib/ransack/search.rb +39 -13
- data/lib/ransack/translate.rb +7 -8
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +5 -5
- data/spec/ransack/adapters/active_record/base_spec.rb +78 -35
- data/spec/ransack/adapters/active_record/context_spec.rb +58 -15
- data/spec/ransack/configuration_spec.rb +18 -18
- data/spec/ransack/dependencies_spec.rb +1 -1
- data/spec/ransack/helpers/form_builder_spec.rb +29 -29
- data/spec/ransack/helpers/form_helper_spec.rb +14 -1
- data/spec/ransack/nodes/condition_spec.rb +21 -2
- data/spec/ransack/predicate_spec.rb +49 -9
- data/spec/ransack/search_spec.rb +178 -143
- data/spec/ransack/translate_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/schema.rb +26 -21
- metadata +15 -11
@@ -0,0 +1,70 @@
|
|
1
|
+
hu:
|
2
|
+
ransack:
|
3
|
+
search: "keresés"
|
4
|
+
predicate: "állítás"
|
5
|
+
and: "és"
|
6
|
+
or: "vagy"
|
7
|
+
any: "bármely"
|
8
|
+
all: "mindegyik"
|
9
|
+
combinator: "combinator"
|
10
|
+
attribute: "attribute"
|
11
|
+
value: "érték"
|
12
|
+
condition: "feltétel"
|
13
|
+
sort: "rendezés"
|
14
|
+
asc: "növekvő"
|
15
|
+
desc: "csökkenő"
|
16
|
+
predicates:
|
17
|
+
eq: "egyenlő"
|
18
|
+
eq_any: "bármelyikkel egyenlő"
|
19
|
+
eq_all: "minddel egyenlő"
|
20
|
+
not_eq: "nem egyenlő"
|
21
|
+
not_eq_any: "nem egyenlő bármelyikkel"
|
22
|
+
not_eq_all: "nem egyenlő egyikkel sem"
|
23
|
+
matches: "egyezik"
|
24
|
+
matches_any: "bármelyikkel egyezik"
|
25
|
+
matches_all: "minddel egyezik"
|
26
|
+
does_not_match: "nem egyezik"
|
27
|
+
does_not_match_any: "nem egyezik semelyikkel"
|
28
|
+
does_not_match_all: "nem egyezik az összessel"
|
29
|
+
lt: "kisebb, mint"
|
30
|
+
lt_any: "bármelyiknél kisebb"
|
31
|
+
lt_all: "mindegyiknél kisebb"
|
32
|
+
lteq: "kisebb vagy egyenlő, mint"
|
33
|
+
lteq_any: "bármelyiknél kisebb vagy egyenlő"
|
34
|
+
lteq_all: "mindegyiknél kisebb vagy egyenlő"
|
35
|
+
gt: "nagyobb, mint"
|
36
|
+
gt_any: "bármelyiknél nagyobb"
|
37
|
+
gt_all: "mindegyiknél nagyobb"
|
38
|
+
gteq: "nagyobb vagy egyenlő, mint"
|
39
|
+
gteq_any: "bármelyiknél nagyobb vagy egyenlő"
|
40
|
+
gteq_all: "mindegyiknél nagyobb vagy egyenlő"
|
41
|
+
in: "értéke"
|
42
|
+
in_any: "értéke bármelyik"
|
43
|
+
in_all: "értéke mindegyik"
|
44
|
+
not_in: "nem ez az értéke"
|
45
|
+
not_in_any: "értéke egyik sem"
|
46
|
+
not_in_all: "értéke nem ezek az elemek"
|
47
|
+
cont: "tartalmazza"
|
48
|
+
cont_any: "bármelyiket tartalmazza"
|
49
|
+
cont_all: "mindet tartalmazza"
|
50
|
+
not_cont: "nem tartalmazza"
|
51
|
+
not_cont_any: "egyiket sem tartalmazza"
|
52
|
+
not_cont_all: "nem tartalmazza mindet"
|
53
|
+
start: "így kezdődik"
|
54
|
+
start_any: "bármelyikkel kezdődik"
|
55
|
+
start_all: "ezekkel kezdődik"
|
56
|
+
not_start: "nem így kezdődik"
|
57
|
+
not_start_any: "nem ezek egyikével kezdődik"
|
58
|
+
not_start_all: "nem ezekkel kezdődik"
|
59
|
+
end: "így végződik"
|
60
|
+
end_any: "bármelyikkel végződik"
|
61
|
+
end_all: "ezekkel végződik"
|
62
|
+
not_end: "nem úgy végződik"
|
63
|
+
not_end_any: "nem ezek egyikével végződik"
|
64
|
+
not_end_all: "nem ezekkel végződik"
|
65
|
+
'true': "igaz"
|
66
|
+
'false': "hamis"
|
67
|
+
present: "létezik"
|
68
|
+
blank: "üres"
|
69
|
+
'null': "null"
|
70
|
+
not_null: "nem null"
|
@@ -0,0 +1,70 @@
|
|
1
|
+
nl:
|
2
|
+
ransack:
|
3
|
+
search: "zoeken"
|
4
|
+
predicate: "eigenschap"
|
5
|
+
and: "en"
|
6
|
+
or: "of"
|
7
|
+
any: "enig"
|
8
|
+
all: "alle"
|
9
|
+
combinator: "combinator"
|
10
|
+
attribute: "attribuut"
|
11
|
+
value: "waarde"
|
12
|
+
condition: "conditie"
|
13
|
+
sort: "sorteren"
|
14
|
+
asc: "oplopend"
|
15
|
+
desc: "aflopend"
|
16
|
+
predicates:
|
17
|
+
eq: "gelijk"
|
18
|
+
eq_any: "gelijk enig"
|
19
|
+
eq_all: "gelijk alle"
|
20
|
+
not_eq: "niet gelijk aan"
|
21
|
+
not_eq_any: "niet gelijk aan enig"
|
22
|
+
not_eq_all: "niet gelijk aan alle"
|
23
|
+
matches: "evenaart"
|
24
|
+
matches_any: "evenaart enig"
|
25
|
+
matches_all: "evenaart alle"
|
26
|
+
does_not_match: "evenaart niet"
|
27
|
+
does_not_match_any: "evenaart niet voor enig"
|
28
|
+
does_not_match_all: "evenaart niet voor alle"
|
29
|
+
lt: "kleiner dan"
|
30
|
+
lt_any: "kleiner dan enig"
|
31
|
+
lt_all: "kleiner dan alle"
|
32
|
+
lteq: "kleiner dan of gelijk aan"
|
33
|
+
lteq_any: "kleiner dan of gelijk aan enig"
|
34
|
+
lteq_all: "kleiner dan of gelijk aan alle"
|
35
|
+
gt: "groter dan"
|
36
|
+
gt_any: "groter dan enig"
|
37
|
+
gt_all: "groter dan alle"
|
38
|
+
gteq: "groter dan or equal to"
|
39
|
+
gteq_any: "groter dan or equal to enig"
|
40
|
+
gteq_all: "groter dan or equal to alle"
|
41
|
+
in: "in"
|
42
|
+
in_any: "in enig"
|
43
|
+
in_all: "in alle"
|
44
|
+
not_in: "niet in"
|
45
|
+
not_in_any: "niet in enig"
|
46
|
+
not_in_all: "niet in alle"
|
47
|
+
cont: "bevat"
|
48
|
+
cont_any: "bevat enig"
|
49
|
+
cont_all: "bevat alle"
|
50
|
+
not_cont: "bevat niet"
|
51
|
+
not_cont_any: "bevat niet enig"
|
52
|
+
not_cont_all: "bevat niet alle"
|
53
|
+
start: "start met"
|
54
|
+
start_any: "start met enig"
|
55
|
+
start_all: "start met alle"
|
56
|
+
not_start: "start niet met"
|
57
|
+
not_start_any: "start niet met enig"
|
58
|
+
not_start_all: "start niet met alle"
|
59
|
+
end: "eindigt met"
|
60
|
+
end_any: "eindigt met enig"
|
61
|
+
end_all: "eindigt met alle"
|
62
|
+
not_end: "eindigt niet met"
|
63
|
+
not_end_any: "eindigt niet met enig"
|
64
|
+
not_end_all: "eindigt niet met alle"
|
65
|
+
'true': "is waar"
|
66
|
+
'false': "is niet waar"
|
67
|
+
present: "is present"
|
68
|
+
blank: "is afwezig"
|
69
|
+
'null': "is null"
|
70
|
+
not_null: "is niet null"
|
@@ -5,8 +5,8 @@ module Ransack
|
|
5
5
|
|
6
6
|
attr_reader :name
|
7
7
|
|
8
|
-
delegate :blank?, :present?, :==, to
|
9
|
-
delegate :engine, to
|
8
|
+
delegate :blank?, :present?, :==, :to => :name
|
9
|
+
delegate :engine, :to => :context
|
10
10
|
|
11
11
|
def initialize(context, name = nil)
|
12
12
|
super(context)
|
@@ -10,20 +10,22 @@ module Ransack
|
|
10
10
|
class << self
|
11
11
|
def extract(context, key, values)
|
12
12
|
attributes, predicate = extract_attributes_and_predicate(key)
|
13
|
-
if attributes.size > 0
|
13
|
+
if attributes.size > 0 && predicate
|
14
14
|
combinator = key.match(/_(or|and)_/) ? $1 : nil
|
15
15
|
condition = self.new(context)
|
16
16
|
condition.build(
|
17
|
-
a
|
18
|
-
p
|
19
|
-
m
|
20
|
-
v
|
17
|
+
:a => attributes,
|
18
|
+
:p => predicate.name,
|
19
|
+
:m => combinator,
|
20
|
+
:v => predicate.wants_array ? Array(values) : [values]
|
21
21
|
)
|
22
22
|
# TODO: Figure out what to do with multiple types of attributes,
|
23
|
-
# if anything.
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
# if anything. Tempted to go with "garbage in, garbage out" here.
|
24
|
+
if predicate.validate(condition.values, condition.default_type)
|
25
|
+
condition
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
@@ -33,7 +35,9 @@ module Ransack
|
|
33
35
|
str = key.dup
|
34
36
|
name = Predicate.detect_and_strip_from_string!(str)
|
35
37
|
predicate = Predicate.named(name)
|
36
|
-
|
38
|
+
unless predicate || Ransack.options[:ignore_unknown_conditions]
|
39
|
+
raise ArgumentError, "No valid predicate for #{key}"
|
40
|
+
end
|
37
41
|
attributes = str.split(/_and_|_or_/)
|
38
42
|
[attributes, predicate]
|
39
43
|
end
|
@@ -169,8 +173,9 @@ module Ransack
|
|
169
173
|
def arel_predicate
|
170
174
|
predicates = attributes.map do |attr|
|
171
175
|
attr.attr.send(
|
172
|
-
|
173
|
-
)
|
176
|
+
arel_predicate_for_attribute(attr),
|
177
|
+
formatted_values_for_attribute(attr)
|
178
|
+
)
|
174
179
|
end
|
175
180
|
|
176
181
|
if predicates.size > 1
|
@@ -203,6 +208,18 @@ module Ransack
|
|
203
208
|
predicate.wants_array ? formatted : formatted.first
|
204
209
|
end
|
205
210
|
|
211
|
+
def arel_predicate_for_attribute(attr)
|
212
|
+
if predicate.arel_predicate === Proc
|
213
|
+
values = casted_values_for_attribute(attr)
|
214
|
+
predicate.arel_predicate.call(
|
215
|
+
predicate.wants_array ? values : values.first
|
216
|
+
)
|
217
|
+
else
|
218
|
+
predicate.arel_predicate
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
|
206
223
|
def default_type
|
207
224
|
predicate.type || (attributes.first && attributes.first.type)
|
208
225
|
end
|
@@ -9,7 +9,7 @@ module Ransack
|
|
9
9
|
i18n_word :condition, :and, :or
|
10
10
|
i18n_alias :c => :condition, :n => :and, :o => :or
|
11
11
|
|
12
|
-
delegate :each, to
|
12
|
+
delegate :each, :to => :values
|
13
13
|
|
14
14
|
def initialize(context, combinator = nil)
|
15
15
|
super(context)
|
@@ -21,7 +21,9 @@ module Ransack
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def translate(key, options = {})
|
24
|
-
super or Translate.attribute(
|
24
|
+
super or Translate.attribute(
|
25
|
+
key.to_s, options.merge(:context => context)
|
26
|
+
)
|
25
27
|
end
|
26
28
|
|
27
29
|
def conditions
|
@@ -159,10 +161,8 @@ module Ransack
|
|
159
161
|
end
|
160
162
|
|
161
163
|
def inspect
|
162
|
-
data = [
|
163
|
-
|
164
|
-
].
|
165
|
-
reject { |e| e[1].blank? }
|
164
|
+
data = [['conditions', conditions], ['combinator', combinator]]
|
165
|
+
.reject { |e| e[1].blank? }
|
166
166
|
.map { |v| "#{v[0]}: #{v[1]}" }
|
167
167
|
.join(', ')
|
168
168
|
"Grouping <#{data}>"
|
data/lib/ransack/nodes/node.rb
CHANGED
data/lib/ransack/nodes/value.rb
CHANGED
data/lib/ransack/predicate.rb
CHANGED
@@ -45,12 +45,11 @@ module Ransack
|
|
45
45
|
@arel_predicate = opts[:arel_predicate]
|
46
46
|
@type = opts[:type]
|
47
47
|
@formatter = opts[:formatter]
|
48
|
-
@validator = opts[:validator] ||
|
49
|
-
|v| v.respond_to?(:empty?) ? !v.empty? : !v.nil?
|
50
|
-
}
|
48
|
+
@validator = opts[:validator] ||
|
49
|
+
lambda { |v| v.respond_to?(:empty?) ? !v.empty? : !v.nil? }
|
51
50
|
@compound = opts[:compound]
|
52
|
-
@wants_array = opts[:wants_array] == true || @compound ||
|
53
|
-
include?(@arel_predicate)
|
51
|
+
@wants_array = opts[:wants_array] == true || @compound ||
|
52
|
+
['in', 'not_in'].include?(@arel_predicate)
|
54
53
|
end
|
55
54
|
|
56
55
|
def eql?(other)
|
data/lib/ransack/ransacker.rb
CHANGED
data/lib/ransack/search.rb
CHANGED
@@ -8,17 +8,19 @@ module Ransack
|
|
8
8
|
|
9
9
|
attr_reader :base, :context
|
10
10
|
|
11
|
-
delegate :object, :klass, to
|
11
|
+
delegate :object, :klass, :to => :context
|
12
12
|
delegate :new_grouping, :new_condition,
|
13
13
|
:build_grouping, :build_condition,
|
14
|
-
:translate, to
|
14
|
+
:translate, :to => :base
|
15
15
|
|
16
16
|
def initialize(object, params = {}, options = {})
|
17
17
|
params = {} unless params.is_a?(Hash)
|
18
|
-
(params ||= {})
|
19
|
-
|
18
|
+
(params ||= {})
|
19
|
+
.delete_if { |k, v| [*v].all? { |i| i.blank? && i != false } }
|
20
|
+
@context = options[:context] || Context.for(object, options)
|
20
21
|
@context.auth_object = options[:auth_object]
|
21
|
-
@base = Nodes::Grouping.new(@context, 'and')
|
22
|
+
@base = Nodes::Grouping.new(@context, options[:grouping] || 'and')
|
23
|
+
@scope_args = {}
|
22
24
|
build(params.with_indifferent_access)
|
23
25
|
end
|
24
26
|
|
@@ -28,11 +30,14 @@ module Ransack
|
|
28
30
|
|
29
31
|
def build(params)
|
30
32
|
collapse_multiparameter_attributes!(params).each do |key, value|
|
31
|
-
|
32
|
-
when 's', 'sorts'
|
33
|
+
if ['s', 'sorts'].include?(key)
|
33
34
|
send("#{key}=", value)
|
34
|
-
|
35
|
-
base.send("#{key}=", value)
|
35
|
+
elsif base.attribute_method?(key)
|
36
|
+
base.send("#{key}=", value)
|
37
|
+
elsif @context.ransackable_scope?(key, @context.object)
|
38
|
+
add_scope(key, value)
|
39
|
+
elsif !Ransack.options[:ignore_unknown_conditions]
|
40
|
+
raise ArgumentError, "Invalid search term #{key}"
|
36
41
|
end
|
37
42
|
end
|
38
43
|
self
|
@@ -57,7 +62,8 @@ module Ransack
|
|
57
62
|
when String
|
58
63
|
self.sorts = [args]
|
59
64
|
else
|
60
|
-
raise ArgumentError,
|
65
|
+
raise ArgumentError,
|
66
|
+
"Invalid argument (#{args.class}) supplied to sorts="
|
61
67
|
end
|
62
68
|
end
|
63
69
|
alias :s= :sorts=
|
@@ -79,20 +85,40 @@ module Ransack
|
|
79
85
|
|
80
86
|
def method_missing(method_id, *args)
|
81
87
|
method_name = method_id.to_s
|
82
|
-
|
83
|
-
if base.attribute_method?(
|
88
|
+
getter_name = method_name.sub(/=$/, '')
|
89
|
+
if base.attribute_method?(getter_name)
|
84
90
|
base.send(method_id, *args)
|
91
|
+
elsif @context.ransackable_scope?(getter_name, @context.object)
|
92
|
+
if method_name =~ /=$/
|
93
|
+
add_scope getter_name, args
|
94
|
+
else
|
95
|
+
@scope_args[method_name]
|
96
|
+
end
|
85
97
|
else
|
86
98
|
super
|
87
99
|
end
|
88
100
|
end
|
89
101
|
|
90
102
|
def inspect
|
91
|
-
|
103
|
+
details = [
|
104
|
+
[:class, klass.name],
|
105
|
+
([:scope, @scope_args] if @scope_args.present?),
|
106
|
+
[:base, base.inspect]
|
107
|
+
].compact.map { |d| d.join(': ') }.join(', ')
|
108
|
+
"Ransack::Search<#{details}>"
|
92
109
|
end
|
93
110
|
|
94
111
|
private
|
95
112
|
|
113
|
+
def add_scope(key, args)
|
114
|
+
if @context.scope_arity(key) == 1
|
115
|
+
@scope_args[key] = args.is_a?(Array) ? args[0] : args
|
116
|
+
else
|
117
|
+
@scope_args[key] = args
|
118
|
+
end
|
119
|
+
@context.chain_scope(key, args)
|
120
|
+
end
|
121
|
+
|
96
122
|
def collapse_multiparameter_attributes!(attrs)
|
97
123
|
attrs.keys.each do |k|
|
98
124
|
if k.include?("(")
|
data/lib/ransack/translate.rb
CHANGED
@@ -5,11 +5,11 @@ I18n.load_path += Dir[File.join(File.dirname(__FILE__), 'locale', '*.yml')]
|
|
5
5
|
module Ransack
|
6
6
|
module Translate
|
7
7
|
def self.word(key, options = {})
|
8
|
-
I18n.translate(:"ransack.#{key}", default
|
8
|
+
I18n.translate(:"ransack.#{key}", :default => key.to_s)
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.predicate(key, options = {})
|
12
|
-
I18n.translate(:"ransack.predicates.#{key}", default
|
12
|
+
I18n.translate(:"ransack.predicates.#{key}", :default => key.to_s)
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.attribute(key, options = {})
|
@@ -47,7 +47,7 @@ module Ransack
|
|
47
47
|
end
|
48
48
|
|
49
49
|
defaults << options.delete(:default) if options[:default]
|
50
|
-
options.reverse_merge! count
|
50
|
+
options.reverse_merge! :count => 1, :default => defaults
|
51
51
|
I18n.translate(defaults.shift, options.merge(interpolations))
|
52
52
|
end
|
53
53
|
|
@@ -60,7 +60,7 @@ module Ransack
|
|
60
60
|
[:"#{context.klass.i18n_scope}.models.#{i18n_key(context.klass)}"] :
|
61
61
|
[:"ransack.associations.#{i18n_key(context.klass)}.#{key}"]
|
62
62
|
defaults << context.traverse(key).model_name.human
|
63
|
-
options = { count
|
63
|
+
options = { :count => 1, :default => defaults }
|
64
64
|
I18n.translate(defaults.shift, options)
|
65
65
|
end
|
66
66
|
|
@@ -75,7 +75,7 @@ module Ransack
|
|
75
75
|
:"ransack.attributes.#{
|
76
76
|
i18n_key(associated_class || context.klass)
|
77
77
|
}.#{attr_name}",
|
78
|
-
default
|
78
|
+
:default => [
|
79
79
|
(
|
80
80
|
if associated_class
|
81
81
|
:"#{associated_class.i18n_scope}.attributes.#{
|
@@ -93,13 +93,12 @@ module Ransack
|
|
93
93
|
if include_associations && associated_class
|
94
94
|
defaults << '%{association_name} %{attr_fallback_name}'
|
95
95
|
interpolations[:association_name] = association(
|
96
|
-
assoc_path,
|
97
|
-
context: context
|
96
|
+
assoc_path, :context => context
|
98
97
|
)
|
99
98
|
else
|
100
99
|
defaults << '%{attr_fallback_name}'
|
101
100
|
end
|
102
|
-
options = { count
|
101
|
+
options = { :count => 1, :default => defaults }
|
103
102
|
I18n.translate(defaults.shift, options.merge(interpolations))
|
104
103
|
end
|
105
104
|
|