Reputation: 267140
I am listing products and I want to be able to pass a hash as my where clause so I can do something like:
filter = {}
filter[:category_id] = @category.id
filter[:is_active] = true
@products = Products.where(filter)
Is it possible to do this somehow?
I also need to add something like this in my where clause:
WHERE price > 100
How could I add that to a filter?
The reason I want to do this is because in the UI I will have a set of optional filters, so then I will use if clauses in my controller to set each filter.
Upvotes: 3
Views: 2263
Reputation: 3779
You could have a bit of fun with scopes: write a scope that's actually a mini predicate builder, sanitizing and pattern-matching strings, and delegating to the standard predicate builder for other scalar types. E.g.
# app/models/concerns/searchable.rb
module Searchable
extend ActiveSupport::Concern
included do
scope :search, ->(params) {
params.inject(self) do |rel, (key, value)|
next rel if value.blank?
case value
when String
rel.where arel_table[key].matches '%%%s%%' % sanitize_sql_like(value)
when Range, Numeric, TrueClass, FalseClass
rel.where key => value
else
raise ArgumentError, "unacceptable search type"
end
end
}
end
end
# app/models/product.rb
class Product < ApplicationRecord
include Searchable
then you can
filter = { name: 'cheese', description: 'aged', age: 42.. }
Product.search(filter) #=> SELECT "products".* FROM products WHERE "products"."name" ILIKE '%cheese%' AND "products"."description" ILIKE '%aged%' AND "products"."age" >= 42
Upvotes: 1
Reputation: 106077
You can pass a hash to where
exactly like you did:
filter = {
category_id: @category_id,
is_active: true
}
@products = Product.where(filter)
Using a hash only works for equality (e.g. category_id = 123
), so you can't put something like price > 100
in there. To add that criteria, just add another where
to the chain:
@product = Product.where(filter).where('price > 100')
Or...
@product = Product.where(filter)
if params[:min_price]
@product = @product.where('price > ?', min_price)
end
Upvotes: 4