This is a problem I'm coming across regularly. Let me explain it by a simplified example:
Say I want to show a search page where results can be filtered by selecting one or multiple product categories. In the view, this looks like:
<%= select_tag("product_categories", options_from_collection_for_select(@product_categories, 'id', 'name'), multiple:true, include_blank:"(all categories)" %>
Now, in the controller, I have something like:
@filtered_products = Product.all
...
if params[:product_categories].present?
@filtered_products = @filtered_products.where(category_id: params[:product_categories].map(&:to_i))
end
...
#etc
However, as it is impossible to deselect a multiselect when it has clicked, there is a blank option. But, when this option is set, params[:product_categories]
contains [""]
. This results in the if-statement to evaluate, and as "".to_i == 0, we only get products with category 0 (which usually is none, as ActiveRecord starts ids from 1 in the database). This is not the desired result, as in fact we want all products when the blank option is selected.
Handling this case is made even more difficult because, it is possible to accidentally select both the blank option and one or multiple other options. So this case needs to be handled as well.
I have changed the if-statement to
if params[:product_categories].present? && params[:product_categories].any? && (params[:product_categories].length > 1 || params[:product_categories].first != "")
...
end
It works, but this code is very ugly. I am wondering if there is a nicer, more DRY, Rails-like way to do this.