So I have a Lot which has_many properties. I'm doing a quick search where the user entered a term into a textbox, params[:q], and I search every field of the lot to see if it matches. I also want to check their properties, and if the property matches, and ONLY return the lot.
I accomplish this, like this
if params[:q]
@property_lots = []
@lots.each do |lot|
@property_lots << lot if lot.properties.where(["name LIKE :query OR value LIKE :query", :query => "%#{params[:q]}%"]).any?
end
@lots = @lots.where(["number LIKE :query OR title LIKE :query OR description LIKE :query OR position LIKE :query OR notes LIKE :query OR notes LIKE :query OR buyer_id LIKE :query OR
display_type LIKE :query OR status LIKE :query", :query => "%#{params[:q]}%"])
@lots = @lots.merge(@property_lots)
@lots.uniq!
end
The problem with this is that it turns the activerecord:relation into an Array, which breaks my pagintation, my scope that is added later, and my reorder. Is there a way to do this without creating an array?
You could define a method in your model to search with a keyword:
def self.search_strategy(string)
string = "%#{string}%"
scope = self.includes(:properties)
scope = scope.where("lots.number ILIKE :q OR lots.title ILIKE :query OR lots.description ILIKE :query OR lots.notes ILIKE :q OR lots.position ILIKE :q OR ILIKE lots.buyer_id ILIKE :q OR lots.display_type ILIKE :q OR lots.status ILIKE :q OR properties.name ILIKE :q OR properties.value ILIKE :q", q: string)
scope
end
And use it like this in your controller:
if params[:q]
@lots = Lot.search_strategy(params[:q])
end
A more flexible version :
def self.search_strategy(string)
string = "%#{string}%"
conditions = []
['number', 'title', 'description', 'notes', 'position', 'buyer_id', 'display_type', 'status'].each do |column_name|
conditions << "lots.#{column_name} ILIKE :q"
end
['name', 'value'].each do |column_name|
conditions << "properties.#{column_name} ILIKE :q"
end
conditions = conditions.join(' OR ')
scope = self.includes(:properties)
scope = scope.where(conditions, q: string)
scope
end
With the version above you can easily add/remove columns to search on ;-)
Here's a "please forgive me for the horrible thing I'm about to do" answer.
After your @lots.uniq!
:
@lots = Lot.find(@lots.map(&:id))
Rails' identity map caching might make this not too terrible, but hopefully someone has something better!!
Looks like identity map is gone in Rails 4... Oh well. :)
if params[:q]
@lots = @lots.joins("LEFT JOIN properties ON properties.lot_id = lots.id").where(["lots.number LIKE :query OR lots.title LIKE :query OR lots.description LIKE :query
OR lots.notes LIKE :query OR lots.display_type LIKE :query OR lots.status LIKE :query OR properties.name LIKE :query OR properties.value LIKE :query", :query => "%#{params[:q]}%"])``
end
Left Join fixed it
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.