Rails: multi-selective filtering with an empty parameter

This is a problem that I encounter regularly. Let me explain this with a simplified example:

Say I want to show a search page where you can filter the results by selecting one or more product categories. In the view, it looks like this:

<%= 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, since it is not possible to deselect multi select when pressed, an empty parameter exists. But, when this parameter is set, params[:product_categories] contains [""] . This leads to the calculation of the if-statement, and as "" .to_i == 0, we get only products with category 0 (usually not, since ActiveRecord runs identifiers from 1 in the database). This is not the desired result, since in fact we want everyone to be when choosing an empty parameter.

Handling this case is even more difficult, because you can randomly select either an empty parameter or one or more other parameters. Therefore, this case also needs to be handled.

I changed the if-statement to

 if params[:product_categories].present? && params[:product_categories].any? && (params[:product_categories].length > 1 || params[:product_categories].first != "") ... end 

This works, but this code is very ugly. I am wondering if there is a nicer, more severe, Rails-like way to do this.

+5
source share
3 answers

If you do not have any categories selected, you can add hidden_field in the same way as product_categories to avoid [""] with a null value in front of your selection 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 process it. It does not need to display (&: id), because "" will be automatically generated at 0 in the request.

 if params[:product_categories] != [""] @filtered_products = @filtered_products.where(category_id: params[:product_categories]) end 

This is why the inline array is always displayed in several choices . I hope this clears your code.

+5
source

Try

 if params[:product_categories].reject!(&:empty?).any? end 
+4
source

Just upgrade Florin a bit.

 params[:product_categories].reject!(&:empty?).any? if params[:product_categories].length > 1 
+4
source

All Articles