这是我经常遇到的一个问题。让我通过一个简化的例子来解释它:
假设我想显示一个搜索页面,可以通过选择一个或多个产品类别来过滤结果。在 View 中,这看起来像:
<%= select_tag("product_categories", options_from_collection_for_select(@product_categories, 'id', 'name'), multiple:true, include_blank:"(all categories)" %>
现在,在 Controller 中,我有类似的东西:
@filtered_products = Product.all
...
if params[:product_categories].present?
@filtered_products = @filtered_products.where(category_id: params[:product_categories].map(&:to_i))
end
...
#etc
但是,由于无法在单击时取消选择多选,因此有一个空白选项。但是,当设置此选项时,
params[:product_categories]
包含 [""]
.这导致要评估的 if 语句,并且由于 "".to_i == 0,我们只能获得类别为 0 的产品(通常为无,因为 ActiveRecord 从数据库中的 1 开始 ids)。这不是我们想要的结果,因为实际上我们想要 全部 选择空白选项时的产品。处理这种情况变得更加困难,因为可能会意外选择空白选项和一个或多个其他选项。所以这个案例也需要处理。
我已将 if 语句更改为
if params[:product_categories].present? && params[:product_categories].any? && (params[:product_categories].length > 1 || params[:product_categories].first != "")
...
end
它有效,但这段代码非常难看。我想知道是否有更好、更 DRY、类似 Rails 的方法来做到这一点。
最佳答案
当您没有选择任何一个类别时,您可以添加 hidden_field
同 product_categories
避免 [""]
在您选择的选项之前为 nil 值。
<%= hidden_field_tag "product_categories" %>
<%= select_tag("product_categories", options_from_collection_for_select(@product_categories, 'id', 'name'), multiple:true, include_blank:"(all categories)" %>
然后去处理。不需要 map(&:id) 因为
""
查询时会自动生成为0。if params[:product_categories] != [""]
@filtered_products = @filtered_products.where(category_id: params[:product_categories])
end
这就是为什么embedded array always showing in multiple select options .我希望这能让你的代码变得干净。
关于ruby-on-rails - rails : multiselect filtering with a blank option,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32626179/