Reputation: 2117
Filtering items by title, created_at dates, but one of them would be empty and it raises an error, how could I handle that?
where("country_translations.title ILIKE ? AND country_translations.created_at > ? AND country_translations.created_at < ?", "%#{search[:title]}%", search[:created_at_gt], search[:created_at_lt])
Upvotes: 0
Views: 117
Reputation: 6121
you can always use scopes in such case, they come handy almost everywhere
scope :filter_by_title, -> (title) { where('title ILIKE ?', "%#{title}%") if title.present? }
scope :filter_by_created_at_lt, -> (date) { where('created_at < ?', date) if date.present? }
scope :filter_by_created_at_gt, -> (date) { where('created_at > ?', date) if date.present? }
Then you can restructure the query as
Model.filter_by_title(search[:title])
.filter_by_created_at_lt(search[:created_at_lt])
.filter_by_created_at_gt(search[:created_at_gt])
Upvotes: 1
Reputation: 1402
It really depends on how you want to handle that.
First of all, I will decompose the query into multiple where
s, that default to an AND operation. This is for readability:
Model.where("country_translations.title ILIKE ?", "%#{search[:title]}%")
.where("country_translations.created_at > ?", search[:created_at_gt])
.where("country_translations.created_at < ?", search[:created_at_lt])
You could either pass default values using the ||
operator, like this:
Model.where("country_translations.title ILIKE ?", "%#{search[:title] || ''}%")
.where("country_translations.created_at > ?", search[:created_at_gt] || Time.now)
.where("country_translations.created_at < ?", search[:created_at_lt] || Time.now)
or you can split this into three filters that have to be applied only when needed:
query = Model.all
query = query.where("country_translations.title ILIKE ?", "%#{search[:title]}%") if search[:title]
query = query.where("country_translations.created_at > ?", search[:created_at_gt]) if search[:created_at_gt]
query = query.where("country_translations.created_at < ?", search[:created_at_lt]) if search[:created_at_lt]
# query now is filtered only with present filters.
Upvotes: 1
Reputation: 14900
You can chain your where
clauses quite easily.
@results = Model.all
@results = @results.where('country_translations.title ILIKE ?', "%#{search[:title]}%") if search[:title].present?
If you're using Postgres you can also use a regex instead of ILIKE to get rid of this %#{}%
stuff.
@results = @results.where('country_translations.title ~* ?', search[:title]) if search[:title].present?
and so on for your other fields.
Upvotes: 1
Reputation: 2289
You can do something like this:
YourModel.where(filter_by_translations_title).where(filter_by_translations_created)
def filter_by_translations_title
['country_translations.title ILIKE ?', search[:title]] if search[:title].present?
end
#...add rest of methods here
Chaining #where
will join all queries via AND
. This way will allow you add as many sub quesries as you want, and control their behavior.
Upvotes: 1