I'm using this workaround to enable something like search(:title_matches_or_description_starts_with => 'foo'). However my solution lifts the functionality that applies the condition from Where#evaluate to Builder (because we need to OR together different kind of predicates and that is out of scope for a single where), so it's not optimal:
module MetaSearch
module MultiAttributes
private
def method_missing(method_id, *args, &block)
if match = matches_multi_attributes_method(method_id)
(args.any? || method_name =~ /=$/) ? set_multi_attributes_method_value(match, args.first) : get_multi_attributes_method_value(match, predicates)
else
super
end
end
def matches_multi_attributes_method(method_id)
attributes = method_id.to_s.split(/_or_/)
attributes.collect do |attribute_with_predicate|
return unless match = matches_attribute_method(attribute_with_predicate)
match.captures
end
end
def get_multi_attributes_method_value(attributes_with_predicates)
search_attributes[multi_attributes_key(attributes_with_predicates)]
end
def set_multi_attributes_method_value(attributes_with_predicates, val)
search_attributes[multi_attributes_key(attributes_with_predicates)] = val
conditions = attributes_with_predicates.collect do |(attribute, predicate)|
where = Where.new(predicate)
casted_val = cast_attributes(where.cast || column_type(attribute), val)
if where.validate(casted_val)
arel_attribute = get_attribute(attribute)
if where.splat_param?
arel_attribute.send(where.predicate, *where.format_param(casted_val))
else
arel_attribute.send(where.predicate, where.format_param(casted_val))
end
end
end.compact
@relation = @relation.where(conditions.inject(nil) {|memo, c| memo ? memo.or(c) : c}) if conditions.any?
end
def multi_attributes_key(attributes_with_predicates)
attributes_with_predicates.collect {|a_w_p| a_w_p.join('_')}.join('_or_')
end
end
Builder.send :include, MultiAttributes
end
I'd like the ability to search multiple attributes given a single search string. I could probably build a custom Where but this seems like a commonly requested feature.
I'm using this workaround to enable something like
search(:title_matches_or_description_starts_with => 'foo')
. However my solution lifts the functionality that applies the condition fromWhere#evaluate
toBuilder
(because we need to OR together different kind of predicates and that is out of scope for a single where), so it's not optimal: