Rails多态关联实现可打标功能时标签表单取消选中报错问题
问题根因
你观察到的tag_ids数组中的空字符串就是报错的直接原因:
这是HTML多选控件的默认行为,浏览器会默认提交一个隐藏的空值字段,保证用户完全不选任何标签时参数中也会存在tag_ids字段触发关联更新。但空字符串传入ActiveRecord关联赋值逻辑时,会被尝试转为整数匹配Tag记录,匹配失败后框架会尝试新建标签关联记录,此时无法正确填充多态关联的taggeable_id/taggeable_type字段,就抛出了Column 'taggeable_id' cannot be null错误。
最简解决方案
直接在强参数中过滤掉tag_ids数组的空值即可,同时还能保留自动清空关联的能力:
修改你的movie_params方法:
def movie_params params.require(:movie).permit(:title, :runtime, :country, :release_year, :sort_title, tag_ids: []) .tap do |permitted_params| if permitted_params[:tag_ids] permitted_params[:tag_ids] = permitted_params[:tag_ids].reject(&:blank?) end end end
上述逻辑会把tag_ids数组中的空字符串全部清除:
- 当用户取消所有标签选中时,
tag_ids会被处理为空数组,ActiveRecord会自动删除该电影的所有标签关联 - 当用户选中部分标签时,仅保留有效标签ID,框架会自动比对原有关联,新增选中的、删除取消选中的标签关联,完全符合你需要的选中/取消选中逻辑。
该修改可以直接复用给Actor模型对应的控制器参数,无需调整其他业务逻辑。
可选替代方案(不推荐)
如果使用Rails 5及以上版本,你也可以在collection_select参数中关闭空值隐藏字段的生成:
<%= form.collection_select(:tag_ids, Tag.order(:name), :id, :name, { include_hidden: false }, { class: 'selectize-tag', multiple: true }) %>
该方案的缺陷是:如果用户取消所有标签选中,浏览器不会提交tag_ids参数,强参数无法捕获到该字段,框架不会触发标签关联更新,原有标签会全部保留,不符合取消选中的需求。
内容的提问来源于stack exchange,提问作者tkhobbes
相关产品推荐
相关产品推荐

