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.
When you have no one categories selected you can add hidden_field
same as product_categories
to avoid [""]
with nil value before your select options.
<%= hidden_field_tag "product_categories" %>
<%= select_tag("product_categories", options_from_collection_for_select(@product_categories, 'id', 'name'), multiple:true, include_blank:"(all categories)" %>
Then to handle it. It does not need to map(&:id) because ""
will be generated into 0 automatically in query.
if params[:product_categories] != [""]
@filtered_products = @filtered_products.where(category_id: params[:product_categories])
end
These is why embedded array always showing in multiple select options. I hope this make clean your code.
Try
if params[:product_categories].reject!(&:empty?).any?
end
Just improving Florin's answer a bit.
params[:product_categories].reject!(&:empty?).any? if params[:product_categories].length > 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With