The shortest answer is tag this method onto your model:
def search_by_fields(q, fields=nil)
sql = fields.map {|field| "#{field} LIKE ?"}.join(' OR ')
parameters = fields.map {"%#{q}%"}
where(sql, *parameters)
end
A longer answer is in a concern!
Using a concern is a great way to provide search functionality to ANY model you choose. Check this out. First create a file in your app/models/concerns/ called searchable.rb with the following code:
#app/models/concerns/searchable.rb
module Searchable
def self.included(base)
base.extend(ClassMethods)
base.include(AdapterAcknowledgeable)
end
module ClassMethods
@@searchable_fields = []
@@searchable_scope = nil
def search(q, method=nil)
search_method = resolve_search_method(method)
self.send(search_method, q)
end
def search_by_fields(q, fields=nil)
fields = searchable_fields unless fields
sql = fields.map {|field| "#{field} LIKE ?"}.join(' OR ')
parameters = fields.map {"%#{q}%"}
where(sql, *parameters)
end
def search_by_scope(q, scope=nil)
scope = searchable_scope unless scope
scope.call(q)
end
def searchable_scope(scope=nil)
@@searchable_scope = scope unless scope.nil?
@@searchable_scope
end
def searchable_fields(*fields)
@@searchable_fields = fields if fields.present?
@@searchable_fields
end
private
def resolve_search_method(method)
method = method.downcase.to_sym unless method.nil?
if method == :searchable_fields ||
searchable_fields.present? && searchable_scope.nil?
:search_by_fields
elsif method == :searchable_scope ||
!searchable_scope.nil? && searchable_fields.empty?
:search_by_scope
else
raise "Unable to determine search method within #{self}, you must declare exactly one search method in the including class"
end
end
end
end
Usage goes like this:
This will enable the all columns foo, bar, fiz and baz to be queried via the SQL WHERE LIKE. By joining them with OR it allows any of them to match the query parameter.
#app/models/my_searchable_model.rb
class MySearchableModel < ActiveRecord::Base
include Searchable
searchable_fields :foo, :bar, :fiz, :bad
end
The concern also enables you to specify a scope with Ruby's lambda syntax like so:
class User < ActiveRecord::Base
include Searchable
searchable_scope ->(q){where("first_name || ' ' || last_name LIKE ?", "%#{q}%")}
end
Note the use of the SQL concatenation operator ||.
Now when we want to search a model that includes the concern:
MySearchableModel.search('foo')