ransack 1.1.0 → 1.2.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 +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
|