ransack 1.1.0 → 1.2.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 +12 -4
- data/CONTRIBUTING.md +10 -4
- data/Gemfile +12 -9
- data/README.md +46 -11
- data/lib/ransack.rb +4 -2
- data/lib/ransack/adapters/active_record.rb +1 -1
- data/lib/ransack/adapters/active_record/3.0/compat.rb +16 -6
- data/lib/ransack/adapters/active_record/3.0/context.rb +32 -16
- data/lib/ransack/adapters/active_record/3.1/context.rb +32 -15
- data/lib/ransack/adapters/active_record/3.2/context.rb +1 -1
- data/lib/ransack/adapters/active_record/base.rb +9 -6
- data/lib/ransack/adapters/active_record/context.rb +193 -2
- data/lib/ransack/configuration.rb +4 -4
- data/lib/ransack/constants.rb +81 -18
- data/lib/ransack/context.rb +27 -12
- data/lib/ransack/helpers/form_builder.rb +126 -91
- data/lib/ransack/helpers/form_helper.rb +34 -12
- data/lib/ransack/naming.rb +2 -1
- data/lib/ransack/nodes/attribute.rb +6 -4
- data/lib/ransack/nodes/bindable.rb +3 -1
- data/lib/ransack/nodes/condition.rb +40 -27
- data/lib/ransack/nodes/grouping.rb +19 -13
- data/lib/ransack/nodes/node.rb +3 -3
- data/lib/ransack/nodes/sort.rb +5 -3
- data/lib/ransack/nodes/value.rb +2 -2
- data/lib/ransack/predicate.rb +18 -9
- data/lib/ransack/ransacker.rb +4 -4
- data/lib/ransack/search.rb +9 -12
- data/lib/ransack/translate.rb +42 -21
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +4 -4
- data/ransack.gemspec +17 -7
- data/spec/blueprints/notes.rb +2 -0
- data/spec/blueprints/people.rb +4 -1
- data/spec/console.rb +3 -3
- data/spec/ransack/adapters/active_record/base_spec.rb +149 -22
- data/spec/ransack/adapters/active_record/context_spec.rb +5 -5
- data/spec/ransack/configuration_spec.rb +17 -8
- data/spec/ransack/dependencies_spec.rb +8 -0
- data/spec/ransack/helpers/form_builder_spec.rb +37 -14
- data/spec/ransack/helpers/form_helper_spec.rb +5 -5
- data/spec/ransack/predicate_spec.rb +6 -3
- data/spec/ransack/search_spec.rb +95 -73
- data/spec/ransack/translate_spec.rb +14 -0
- data/spec/spec_helper.rb +14 -8
- data/spec/support/en.yml +6 -0
- data/spec/support/schema.rb +76 -31
- metadata +48 -29
@@ -1,62 +1,62 @@
|
|
1
1
|
require 'action_view'
|
2
2
|
|
3
|
+
require 'simple_form' if
|
4
|
+
(ENV['RANSACK_FORM_BUILDER'] || '').match('SimpleForm')
|
5
|
+
|
3
6
|
module Ransack
|
4
7
|
module Helpers
|
5
|
-
class FormBuilder <
|
8
|
+
class FormBuilder < (ENV['RANSACK_FORM_BUILDER'].try(:constantize) ||
|
9
|
+
ActionView::Helpers::FormBuilder)
|
10
|
+
|
6
11
|
def label(method, *args, &block)
|
7
12
|
options = args.extract_options!
|
8
13
|
text = args.first
|
9
14
|
i18n = options[:i18n] || {}
|
10
|
-
text ||= object.translate(
|
15
|
+
text ||= object.translate(
|
16
|
+
method, i18n.reverse_merge(include_associations: true)
|
17
|
+
) if object.respond_to? :translate
|
11
18
|
super(method, text, options, &block)
|
12
19
|
end
|
13
20
|
|
14
|
-
def submit(value=nil, options={})
|
21
|
+
def submit(value = nil, options = {})
|
15
22
|
value, options = nil, value if value.is_a?(Hash)
|
16
23
|
value ||= Translate.word(:search).titleize
|
17
24
|
super(value, options)
|
18
25
|
end
|
19
26
|
|
20
|
-
def attribute_select(options =
|
21
|
-
|
27
|
+
def attribute_select(options = nil, html_options = nil, action = nil)
|
28
|
+
options = options || {}
|
29
|
+
html_options = html_options || {}
|
30
|
+
action = action || 'search'
|
31
|
+
default = options.delete(:default)
|
32
|
+
raise ArgumentError, formbuilder_error_message(
|
33
|
+
"#{action}_select") unless object.respond_to?(:context)
|
22
34
|
options[:include_blank] = true unless options.has_key?(:include_blank)
|
23
35
|
bases = [''] + association_array(options[:associations])
|
24
36
|
if bases.size > 1
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
37
|
+
collection = attribute_collection_for_bases(action, bases)
|
38
|
+
object.name ||= default if can_use_default?(
|
39
|
+
default, :name, mapped_values(collection.flatten(2))
|
40
|
+
)
|
41
|
+
template_grouped_collection_select(collection, options, html_options)
|
29
42
|
else
|
30
|
-
collection =
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
)
|
43
|
+
collection = collection_for_base(action, bases.first)
|
44
|
+
object.name ||= default if can_use_default?(
|
45
|
+
default, :name, mapped_values(collection)
|
46
|
+
)
|
47
|
+
template_collection_select(:name, collection, options, html_options)
|
35
48
|
end
|
36
49
|
end
|
37
50
|
|
51
|
+
def sort_direction_select(options = {}, html_options = {})
|
52
|
+
raise ArgumentError, formbuilder_error_message(
|
53
|
+
'sort_direction') unless object.respond_to?(:context)
|
54
|
+
template_collection_select(:dir, sort_array, options, html_options)
|
55
|
+
end
|
56
|
+
|
38
57
|
def sort_select(options = {}, html_options = {})
|
39
|
-
|
40
|
-
options
|
41
|
-
bases = [''] + association_array(options[:associations])
|
42
|
-
if bases.size > 1
|
43
|
-
@template.grouped_collection_select(
|
44
|
-
@object_name, :name, sortable_attribute_collection_for_bases(bases), :last, :first, :first, :last,
|
45
|
-
objectify_options(options), @default_options.merge(html_options)
|
46
|
-
) + @template.collection_select(
|
47
|
-
@object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last,
|
48
|
-
objectify_options(options), @default_options.merge(html_options)
|
49
|
-
)
|
50
|
-
else
|
51
|
-
collection = sortable_attribute_collection_for_base(bases.first)
|
52
|
-
@template.collection_select(
|
53
|
-
@object_name, :name, collection, :first, :last,
|
54
|
-
objectify_options(options), @default_options.merge(html_options)
|
55
|
-
) + @template.collection_select(
|
56
|
-
@object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last,
|
57
|
-
objectify_options(options), @default_options.merge(html_options)
|
58
|
-
)
|
59
|
-
end
|
58
|
+
attribute_select(options, html_options, 'sort') +
|
59
|
+
sort_direction_select(options, html_options)
|
60
60
|
end
|
61
61
|
|
62
62
|
def sort_fields(*args, &block)
|
@@ -98,37 +98,70 @@ module Ransack
|
|
98
98
|
name = "#{options[:object_name] || object_name}[#{name}]"
|
99
99
|
output = ActiveSupport::SafeBuffer.new
|
100
100
|
objects.each do |child|
|
101
|
-
output << @template.fields_for("#{name}[#{
|
101
|
+
output << @template.fields_for("#{name}[#{
|
102
|
+
options[:child_index] || nested_child_index(name)
|
103
|
+
}]", child, options, &block)
|
102
104
|
end
|
103
105
|
output
|
104
106
|
end
|
105
107
|
|
106
108
|
def predicate_select(options = {}, html_options = {})
|
107
109
|
options[:compounds] = true if options[:compounds].nil?
|
108
|
-
|
110
|
+
if ::ActiveRecord::VERSION::STRING >= "4"
|
111
|
+
default = options.delete(:default) || 'cont'
|
112
|
+
else
|
113
|
+
default = options.delete(:default) || 'eq'
|
114
|
+
end
|
115
|
+
|
116
|
+
keys = options[:compounds] ? Predicate.names :
|
117
|
+
Predicate.names.reject { |k| k.match(/_(any|all)$/) }
|
109
118
|
if only = options[:only]
|
110
119
|
if only.respond_to? :call
|
111
|
-
keys = keys.select {|k| only.call(k)}
|
120
|
+
keys = keys.select { |k| only.call(k) }
|
112
121
|
else
|
113
122
|
only = Array.wrap(only).map(&:to_s)
|
114
|
-
keys = keys.select {|k| only.include? k.sub(/_(any|all)$/, '')}
|
123
|
+
keys = keys.select { |k| only.include? k.sub(/_(any|all)$/, '') }
|
115
124
|
end
|
116
125
|
end
|
126
|
+
collection = keys.map { |k| [k, Translate.predicate(k)] }
|
127
|
+
object.predicate ||= Predicate.named(default) if can_use_default?(
|
128
|
+
default, :predicate, keys
|
129
|
+
)
|
130
|
+
template_collection_select(:p, collection, options, html_options)
|
131
|
+
end
|
117
132
|
|
118
|
-
|
119
|
-
|
133
|
+
def combinator_select(options = {}, html_options = {})
|
134
|
+
template_collection_select(:m, combinator_choices, options, html_options)
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def template_grouped_collection_select(collection, options, html_options)
|
140
|
+
@template.grouped_collection_select(
|
141
|
+
@object_name, :name, collection, :last, :first, :first, :last,
|
120
142
|
objectify_options(options), @default_options.merge(html_options)
|
121
|
-
|
143
|
+
)
|
122
144
|
end
|
123
145
|
|
124
|
-
def
|
146
|
+
def template_collection_select(name, collection, options, html_options)
|
125
147
|
@template.collection_select(
|
126
|
-
@object_name,
|
148
|
+
@object_name, name, collection, :first, :last,
|
127
149
|
objectify_options(options), @default_options.merge(html_options)
|
128
|
-
|
150
|
+
)
|
129
151
|
end
|
130
152
|
|
131
|
-
|
153
|
+
def can_use_default?(default, attribute, values)
|
154
|
+
object.respond_to?("#{attribute}=") && default &&
|
155
|
+
values.include?(default.to_s)
|
156
|
+
end
|
157
|
+
|
158
|
+
def mapped_values(values)
|
159
|
+
values.map { |v| v.is_a?(Array) ? v.first : nil }.compact
|
160
|
+
end
|
161
|
+
|
162
|
+
def sort_array
|
163
|
+
[['asc', object.translate('asc')], ['desc', object.translate('desc')]]
|
164
|
+
end
|
132
165
|
|
133
166
|
def combinator_choices
|
134
167
|
if Nodes::Condition === object
|
@@ -139,70 +172,72 @@ module Ransack
|
|
139
172
|
end
|
140
173
|
|
141
174
|
def association_array(obj, prefix = nil)
|
142
|
-
([prefix] +
|
175
|
+
([prefix] + association_object(obj))
|
176
|
+
.compact
|
177
|
+
.flatten
|
178
|
+
.map { |v| [prefix, v].compact.join('_') }
|
179
|
+
end
|
180
|
+
|
181
|
+
def association_object(obj)
|
182
|
+
case obj
|
143
183
|
when Array
|
144
184
|
obj
|
145
185
|
when Hash
|
146
|
-
obj
|
147
|
-
case value
|
148
|
-
when Array, Hash
|
149
|
-
association_array(value, key.to_s)
|
150
|
-
else
|
151
|
-
[key.to_s, [key, value].join('_')]
|
152
|
-
end
|
153
|
-
end
|
186
|
+
association_hash(obj)
|
154
187
|
else
|
155
188
|
[obj]
|
156
|
-
end
|
157
|
-
compact.flatten.map { |v| [prefix, v].compact.join('_') }
|
189
|
+
end
|
158
190
|
end
|
159
191
|
|
160
|
-
def
|
161
|
-
|
192
|
+
def association_hash(obj)
|
193
|
+
obj.map do |key, value|
|
194
|
+
case value
|
195
|
+
when Array, Hash
|
196
|
+
association_array(value, key.to_s)
|
197
|
+
else
|
198
|
+
[key.to_s, [key, value].join('_')]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def attribute_collection_for_bases(action, bases)
|
204
|
+
bases.map { |base| get_attribute_element(action, base) }.compact
|
205
|
+
end
|
206
|
+
|
207
|
+
def get_attribute_element(action, base)
|
208
|
+
begin
|
209
|
+
[Translate.association(base, context: object.context),
|
210
|
+
collection_for_base(action, base)]
|
211
|
+
rescue UntraversableAssociationError => e
|
212
|
+
nil
|
213
|
+
end
|
162
214
|
end
|
163
215
|
|
164
|
-
def attribute_collection_for_base(attributes, base=nil)
|
216
|
+
def attribute_collection_for_base(attributes, base = nil)
|
165
217
|
attributes.map do |c|
|
166
|
-
[
|
167
|
-
|
168
|
-
|
218
|
+
[attr_from_base_and_column(base, c),
|
219
|
+
Translate.attribute(
|
220
|
+
attr_from_base_and_column(base, c),
|
221
|
+
context: object.context
|
222
|
+
)
|
169
223
|
]
|
170
224
|
end
|
171
225
|
end
|
172
226
|
|
173
|
-
def
|
174
|
-
attribute_collection_for_base(
|
227
|
+
def collection_for_base(action, base)
|
228
|
+
attribute_collection_for_base(
|
229
|
+
object.context.send("#{action}able_attributes", base), base)
|
175
230
|
end
|
176
231
|
|
177
|
-
def
|
178
|
-
|
232
|
+
def attr_from_base_and_column(base, column)
|
233
|
+
[base, column].reject { |v| v.blank? }.join('_')
|
179
234
|
end
|
180
235
|
|
181
|
-
def
|
182
|
-
|
183
|
-
|
184
|
-
[
|
185
|
-
Translate.association(base, :context => object.context),
|
186
|
-
sortable_attribute_collection_for_base(base)
|
187
|
-
]
|
188
|
-
rescue UntraversableAssociationError => e
|
189
|
-
nil
|
190
|
-
end
|
191
|
-
end.compact
|
236
|
+
def formbuilder_error_message(action)
|
237
|
+
"#{action.sub('search', 'attribute')
|
238
|
+
} must be called inside a search FormBuilder!"
|
192
239
|
end
|
193
240
|
|
194
|
-
def searchable_attribute_collection_for_bases(bases)
|
195
|
-
bases.map do |base|
|
196
|
-
begin
|
197
|
-
[
|
198
|
-
Translate.association(base, :context => object.context),
|
199
|
-
searchable_attribute_collection_for_base(base)
|
200
|
-
]
|
201
|
-
rescue UntraversableAssociationError => e
|
202
|
-
nil
|
203
|
-
end
|
204
|
-
end.compact
|
205
|
-
end
|
206
241
|
end
|
207
242
|
end
|
208
|
-
end
|
243
|
+
end
|
@@ -6,16 +6,24 @@ module Ransack
|
|
6
6
|
if record.is_a?(Ransack::Search)
|
7
7
|
search = record
|
8
8
|
options[:url] ||= polymorphic_path(search.klass)
|
9
|
-
elsif record.is_a?(Array) &&
|
10
|
-
|
9
|
+
elsif record.is_a?(Array) &&
|
10
|
+
(search = record.detect { |o| o.is_a?(Ransack::Search) })
|
11
|
+
options[:url] ||= polymorphic_path(
|
12
|
+
record.map { |o| o.is_a?(Ransack::Search) ? o.klass : o }
|
13
|
+
)
|
11
14
|
else
|
12
|
-
raise ArgumentError,
|
15
|
+
raise ArgumentError,
|
16
|
+
"No Ransack::Search object was provided to search_form_for!"
|
13
17
|
end
|
14
18
|
options[:html] ||= {}
|
15
19
|
html_options = {
|
16
|
-
:
|
17
|
-
|
18
|
-
|
20
|
+
class: options[:class].present? ?
|
21
|
+
"#{options[:class]}" :
|
22
|
+
"#{search.klass.to_s.underscore}_search",
|
23
|
+
id: options[:id].present? ?
|
24
|
+
"#{options[:id]}" :
|
25
|
+
"#{search.klass.to_s.underscore}_search",
|
26
|
+
method: :get
|
19
27
|
}
|
20
28
|
options[:as] ||= 'q'
|
21
29
|
options[:html].reverse_merge!(html_options)
|
@@ -31,15 +39,23 @@ module Ransack
|
|
31
39
|
search = search.first
|
32
40
|
end
|
33
41
|
|
34
|
-
raise TypeError, "First argument must be a Ransack::Search!" unless
|
42
|
+
raise TypeError, "First argument must be a Ransack::Search!" unless
|
43
|
+
Search === search
|
35
44
|
|
36
|
-
search_params = params[search.context.search_key] ||
|
45
|
+
search_params = params[search.context.search_key] ||
|
46
|
+
{}.with_indifferent_access
|
37
47
|
|
38
48
|
attr_name = attribute.to_s
|
39
49
|
|
40
|
-
name = (
|
50
|
+
name = (
|
51
|
+
if args.size > 0 && !args.first.is_a?(Hash)
|
52
|
+
args.shift.to_s
|
53
|
+
else
|
54
|
+
Translate.attribute(attr_name, context: search.context)
|
55
|
+
end
|
56
|
+
)
|
41
57
|
|
42
|
-
if existing_sort = search.sorts.detect {|s| s.name == attr_name}
|
58
|
+
if existing_sort = search.sorts.detect { |s| s.name == attr_name }
|
43
59
|
prev_attr, prev_dir = existing_sort.name, existing_sort.dir
|
44
60
|
end
|
45
61
|
|
@@ -57,7 +73,8 @@ module Ransack
|
|
57
73
|
css = ['sort_link', current_dir].compact.join(' ')
|
58
74
|
html_options[:class] = [css, html_options[:class]].compact.join(' ')
|
59
75
|
query_hash = {}
|
60
|
-
query_hash[search.context.search_key] = search_params
|
76
|
+
query_hash[search.context.search_key] = search_params
|
77
|
+
.merge(s: "#{attr_name} #{new_dir}")
|
61
78
|
options.merge!(query_hash)
|
62
79
|
options_for_url = params.merge options
|
63
80
|
|
@@ -67,9 +84,14 @@ module Ransack
|
|
67
84
|
url_for(options_for_url)
|
68
85
|
end
|
69
86
|
|
70
|
-
link_to
|
87
|
+
link_to(
|
88
|
+
[ERB::Util.h(name), order_indicator_for(current_dir)]
|
89
|
+
.compact
|
90
|
+
.join(' ')
|
91
|
+
.html_safe,
|
71
92
|
url,
|
72
93
|
html_options
|
94
|
+
)
|
73
95
|
end
|
74
96
|
|
75
97
|
private
|
data/lib/ransack/naming.rb
CHANGED
@@ -23,7 +23,8 @@ module Ransack
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class Name < String
|
26
|
-
attr_reader :singular, :plural, :element, :collection, :partial_path,
|
26
|
+
attr_reader :singular, :plural, :element, :collection, :partial_path,
|
27
|
+
:human, :param_key, :route_key, :i18n_key
|
27
28
|
alias_method :cache_key, :collection
|
28
29
|
|
29
30
|
def initialize
|
@@ -5,8 +5,8 @@ module Ransack
|
|
5
5
|
|
6
6
|
attr_reader :name
|
7
7
|
|
8
|
-
delegate :blank?, :present?, :==, :
|
9
|
-
delegate :engine, :
|
8
|
+
delegate :blank?, :present?, :==, to: :name
|
9
|
+
delegate :engine, to: :context
|
10
10
|
|
11
11
|
def initialize(context, name = nil)
|
12
12
|
super(context)
|
@@ -19,7 +19,9 @@ module Ransack
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def valid?
|
22
|
-
bound? && attr
|
22
|
+
bound? && attr &&
|
23
|
+
context.klassify(parent).ransackable_attributes(context.auth_object)
|
24
|
+
.include?(attr_name)
|
23
25
|
end
|
24
26
|
|
25
27
|
def type
|
@@ -50,4 +52,4 @@ module Ransack
|
|
50
52
|
|
51
53
|
end
|
52
54
|
end
|
53
|
-
end
|
55
|
+
end
|
@@ -5,7 +5,9 @@ module Ransack
|
|
5
5
|
attr_accessor :parent, :attr_name
|
6
6
|
|
7
7
|
def attr
|
8
|
-
@attr ||= ransacker ?
|
8
|
+
@attr ||= ransacker ?
|
9
|
+
ransacker.attr_from(self) :
|
10
|
+
context.table_for(parent)[attr_name]
|
9
11
|
end
|
10
12
|
alias :arel_attribute :attr
|
11
13
|
|
@@ -2,9 +2,10 @@ module Ransack
|
|
2
2
|
module Nodes
|
3
3
|
class Condition < Node
|
4
4
|
i18n_word :attribute, :predicate, :combinator, :value
|
5
|
-
i18n_alias :a => :attribute, :p => :predicate,
|
5
|
+
i18n_alias :a => :attribute, :p => :predicate,
|
6
|
+
:m => :combinator, :v => :value
|
6
7
|
|
7
|
-
|
8
|
+
attr_accessor :predicate
|
8
9
|
|
9
10
|
class << self
|
10
11
|
def extract(context, key, values)
|
@@ -13,14 +14,16 @@ module Ransack
|
|
13
14
|
combinator = key.match(/_(or|and)_/) ? $1 : nil
|
14
15
|
condition = self.new(context)
|
15
16
|
condition.build(
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
17
|
+
a: attributes,
|
18
|
+
p: predicate.name,
|
19
|
+
m: combinator,
|
20
|
+
v: predicate.wants_array ? Array(values) : [values]
|
20
21
|
)
|
21
|
-
# TODO: Figure out what to do with multiple types of attributes,
|
22
|
+
# TODO: Figure out what to do with multiple types of attributes,
|
23
|
+
# if anything.
|
22
24
|
# Tempted to go with "garbage in, garbage out" on this one
|
23
|
-
predicate.validate(condition.values, condition.default_type) ?
|
25
|
+
predicate.validate(condition.values, condition.default_type) ?
|
26
|
+
condition : nil
|
24
27
|
end
|
25
28
|
end
|
26
29
|
|
@@ -37,7 +40,8 @@ module Ransack
|
|
37
40
|
end
|
38
41
|
|
39
42
|
def valid?
|
40
|
-
attributes.detect(&:valid?) && predicate && valid_arity? &&
|
43
|
+
attributes.detect(&:valid?) && predicate && valid_arity? &&
|
44
|
+
predicate.validate(values, default_type) && valid_combinator?
|
41
45
|
end
|
42
46
|
|
43
47
|
def valid_arity?
|
@@ -62,7 +66,8 @@ module Ransack
|
|
62
66
|
self.attributes << attr if attr.valid?
|
63
67
|
end
|
64
68
|
else
|
65
|
-
raise ArgumentError,
|
69
|
+
raise ArgumentError,
|
70
|
+
"Invalid argument (#{args.class}) supplied to attributes="
|
66
71
|
end
|
67
72
|
end
|
68
73
|
alias :a= :attributes=
|
@@ -85,7 +90,8 @@ module Ransack
|
|
85
90
|
self.values << val
|
86
91
|
end
|
87
92
|
else
|
88
|
-
raise ArgumentError,
|
93
|
+
raise ArgumentError,
|
94
|
+
"Invalid argument (#{args.class}) supplied to values="
|
89
95
|
end
|
90
96
|
end
|
91
97
|
alias :v= :values=
|
@@ -95,7 +101,7 @@ module Ransack
|
|
95
101
|
end
|
96
102
|
|
97
103
|
def combinator=(val)
|
98
|
-
@combinator = ['and', 'or'].detect {|v| v == val.to_s} || nil
|
104
|
+
@combinator = ['and', 'or'].detect { |v| v == val.to_s } || nil
|
99
105
|
end
|
100
106
|
alias :m= :combinator=
|
101
107
|
alias :m :combinator
|
@@ -113,7 +119,9 @@ module Ransack
|
|
113
119
|
end
|
114
120
|
|
115
121
|
def value
|
116
|
-
predicate.wants_array ?
|
122
|
+
predicate.wants_array ?
|
123
|
+
values.map { |v| v.cast(default_type) } :
|
124
|
+
values.first.cast(default_type)
|
117
125
|
end
|
118
126
|
|
119
127
|
def build(params)
|
@@ -131,7 +139,8 @@ module Ransack
|
|
131
139
|
end
|
132
140
|
|
133
141
|
def key
|
134
|
-
@key ||= attributes.map(&:name).join("_#{combinator}_") +
|
142
|
+
@key ||= attributes.map(&:name).join("_#{combinator}_") +
|
143
|
+
"_#{predicate.name}"
|
135
144
|
end
|
136
145
|
|
137
146
|
def eql?(other)
|
@@ -152,11 +161,6 @@ module Ransack
|
|
152
161
|
end
|
153
162
|
alias :p= :predicate_name=
|
154
163
|
|
155
|
-
def predicate=(predicate)
|
156
|
-
@predicate = predicate
|
157
|
-
predicate
|
158
|
-
end
|
159
|
-
|
160
164
|
def predicate_name
|
161
165
|
predicate.name if predicate
|
162
166
|
end
|
@@ -164,7 +168,9 @@ module Ransack
|
|
164
168
|
|
165
169
|
def arel_predicate
|
166
170
|
predicates = attributes.map do |attr|
|
167
|
-
attr.attr.send(
|
171
|
+
attr.attr.send(
|
172
|
+
predicate.arel_predicate, formatted_values_for_attribute(attr)
|
173
|
+
)
|
168
174
|
end
|
169
175
|
|
170
176
|
if predicates.size > 1
|
@@ -180,16 +186,17 @@ module Ransack
|
|
180
186
|
end
|
181
187
|
|
182
188
|
def validated_values
|
183
|
-
values.select {|v| predicate.validator.call(v.value)}
|
189
|
+
values.select { |v| predicate.validator.call(v.value) }
|
184
190
|
end
|
185
191
|
|
186
192
|
def casted_values_for_attribute(attr)
|
187
|
-
validated_values.map {|v| v.cast(predicate.type || attr.type)}
|
193
|
+
validated_values.map { |v| v.cast(predicate.type || attr.type) }
|
188
194
|
end
|
189
195
|
|
190
196
|
def formatted_values_for_attribute(attr)
|
191
197
|
formatted = casted_values_for_attribute(attr).map do |val|
|
192
|
-
val = attr.ransacker.formatter.call(val) if
|
198
|
+
val = attr.ransacker.formatter.call(val) if
|
199
|
+
attr.ransacker && attr.ransacker.formatter
|
193
200
|
val = predicate.format(val)
|
194
201
|
val
|
195
202
|
end
|
@@ -201,9 +208,15 @@ module Ransack
|
|
201
208
|
end
|
202
209
|
|
203
210
|
def inspect
|
204
|
-
data =
|
205
|
-
|
206
|
-
|
211
|
+
data = [
|
212
|
+
['attributes', a.try(:map, &:name)],
|
213
|
+
['predicate', p],
|
214
|
+
['combinator', m],
|
215
|
+
['values', v.try(:map, &:value)]
|
216
|
+
]
|
217
|
+
.reject { |e| e[1].blank? }
|
218
|
+
.map { |v| "#{v[0]}: #{v[1]}" }
|
219
|
+
.join(', ')
|
207
220
|
"Condition <#{data}>"
|
208
221
|
end
|
209
222
|
|
@@ -216,4 +229,4 @@ module Ransack
|
|
216
229
|
|
217
230
|
end
|
218
231
|
end
|
219
|
-
end
|
232
|
+
end
|