我正在向控制器发送一组关联ID,比如说foo_ids
。为了允许一组值,我使用:
params.permit(foo_ids: [])
现在,问题是如果我发送一个foo_ids
的空数组,则忽略该参数。不应该将所有foos
清空为空数组,而是保持关联,因为不允许使用foo_ids
。
这可能是因为an empty array is converted to nil in rails,并且忽略了nil值,因为强参数正在查找标量值数组,而不是单个标量值。
有人能建议一个解决这个问题的好方法吗?谢谢!
其他信息
在更新控制器操作中,我需要能够处理两种情况。我需要能够将foo_ids
设置为空数组。如果我只想更新另一个字段,我还需要能够忽略foo_ids
。如果nil对第二种情况不起作用,则将foo_ids
设置为空数组。
答案 0 :(得分:32)
这已经很晚了,但我自己也遇到了这个问题。我通过在permit语句中包含标量版本和数组版本来解决它,如下所示:
params.require(:photo).permit(:tags, tags: [])
仅供参考 - 已同时拥有相同的许可声明 - 如果你链接它们,它会因某种原因被抛弃。
编辑:我刚注意到通过此方法提交的空数组将变为零 - 我现在有一堆字段应为空数组,这些字段为零。所以我发布的解决方案实际上并不适用于我。编辑第二个:我以为我已经添加了这个,但是这个问题与Rails在params哈希上执行deep_munge有关。此评论解释了如何修复它:https://stackoverflow.com/a/25428800/130592
答案 1 :(得分:19)
我所采取的临时解决方案是:
params[:foo_ids] ||= [] if params.has_key?(:foo_ids)
params.permit(foo_ids: [])
此处,foo_ids
仅在传递时设置为空数组。如果未在请求中传递,则忽略它。
我仍然希望找到一个更好的解决方案,因为这种事情在我正在进行的项目中会非常普遍 - 如果你有任何建议,请提出更好的建议。
答案 2 :(得分:0)
我最近遇到了同样的问题,但这里没有一个答案对我有用。这是我的解决方案。如果你有javascript处理HTTP请求,这也可能对你有用。
在您的客户方:
if (photo.tags.length === 0){
photo.tags = ["null"]
}
在你的PhotosController上
def photo_params
p = params.require(:photo).permit(tags: [])
p["tags"].reject! { |tag| tag == "null" }
p
end
答案 3 :(得分:0)
此解决方案不适用于所有情况:
params.require(:photo).permit(:tags, tags: [])
例如,如果您使用的是MongoDB,则有一个tag_ids数组,该数组将id存储在has_many集合中,如果您在模型中为该属性指定“ type:Array”,则tag_ids属性必须是一个数组。因此,即使执行以下操作,也无法发送带有nil值的tag_id:
params.require(:photo).permit(:tag_ids, tag_ids: [])
Mongoid,MongoDB的官方Ruby适配器,会抱怨tag_ids的值必须是数组。
解决方案是您确实可以通过表单发送一个空数组!而且不需要是json请求。您可以在表单上简单地使用remote:true并通过以下类型发送它::js。怎么做?简单。只需在表单中添加一个隐藏的输入并将其值设置为空字符串即可:
<%= form_for @user, remote: true, html: { class: 'form' } do |f| %>
<%= select_tag("#{f.object_name}[tag_ids][]", options_for_select(Tag.all.collect {|t| [t.name, c.id]}, selected: f.object.tag_ids), { class: 'form-control', multiple: 'multiple' }) %>
<%= hidden_field_tag "#{f.object_name}[tag_ids][]", '' %>
<%= f.submit class: 'btn ink-reaction btn-raised btn-primary' %>
<% end %>
这是关键:
<%= hidden_field_tag "#{f.object_name}[tag_ids][]", '' %>
您的属性将作为空数组存储在数据库中。请注意,我仅使用Mongoid进行了此测试,但我认为它在ActiveRecord中具有相同的功能。
答案 4 :(得分:0)
尽管在JS中构建了一个多部分的FormData,但我遇到了与Donato相似的解决方案。诀窍是在数组中放入一个空字符串。
const formData = new FormData()
formData.append('dish[tag_ids][]', '')
在控制器端,参数以"dish"=>{"tag_ids"=>[""]}
的形式到达,dish.update将其解释为“删除所有标签”。