【问题标题】:Rails - Strong parameters with empty arraysRails - 具有空数组的强参数
【发布时间】:2013-12-08 11:36:53
【问题描述】:

我正在向我的控制器发送一组关联 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 设置为空数组。

【问题讨论】:

    标签: ruby-on-rails strong-parameters


    【解决方案1】:

    这已经很晚了,但我自己也遇到了这个问题。我通过在 permit 语句中同时包含标量版本和数组版本来解决它,如下所示:

    params.require(:photo).permit(:tags, tags: [])
    

    仅供参考 - 它必须将两者放在同一个许可声明中 - 如果将它们链接起来,它会由于某种原因被丢弃。

    编辑:我刚刚注意到通过此方法提交的空数组将变为 nil - 我现在有一堆字段应该是空数组,它们是 nil。所以我发布的解决方案实际上并不适合我。

    编辑第二个:以为我已经添加了这个,但这个问题与 Rails 在参数哈希上执行 deep_munge 有关。此评论解释了如何解决它:https://stackoverflow.com/a/25428800/130592

    【讨论】:

      【解决方案2】:

      我得出的临时解决方案是:

      params[:foo_ids] ||= [] if params.has_key?(:foo_ids)
      params.permit(foo_ids: [])
      

      这里,foo_ids 仅在通过时才设置为空数组。如果没有在请求中传递,则忽略。

      我仍然希望找到更好的解决方案,因为这种事情在我正在从事的项目中很常见 - 如果您有任何想法,请提出更好的想法。

      【讨论】:

      • 我正在考虑一个猴子补丁 before_filter 我会为所有以“_ids”结尾的键做一些事情来解决这个问题。想法?
      • 那行得通。在某些情况下,我需要对嵌套在哈希中的参数执行此操作,因此您可能还需要根据您的使用情况来处理这些情况。
      【解决方案3】:

      此解决方案不适用于所有情况:

      params.require(:photo).permit(:tags, tags: [])
      

      例如,如果您使用的是 MongoDB,并且您有一个 tag_ids 数组,该数组将 id 存储在一个 has_many 集合中,如果您在模型中为属性指定“type: Array”,则您的 tag_ids 属性必须是一个数组。因此,即使您这样做,也无法发送带有 nil 值的 tag_ids:

       params.require(:photo).permit(:tag_ids, tag_ids: [])
      

      MongoDB 的官方 Ruby 适配器 Mongoid 会抱怨 tag_ids 的值必须是一个数组。

      解决方案是您确实可以通过表单发送一个空数组!它不需要是一个 json 请求。您可以在表单上简单地使用 remote:true 并通过 type::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】:

        我最近遇到了同样的问题,但这里没有一个答案对我有用。这是我的解决方案。如果您有 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
        

        【讨论】:

          【解决方案5】:

          我遇到了同样的问题,并找到了与 Donato 类似的解决方案,尽管是在 JS 中构建多部分 FormData 时。诀窍是在数组中放入一个空字符串。

          const formData = new FormData()
          formData.append('dish[tag_ids][]', '')
          

          在控制器端,params 以"dish"=&gt;{"tag_ids"=&gt;[""]} 到达,dish.update 将其解释为“删除所有标签”。

          【讨论】:

            猜你喜欢
            • 2014-01-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-09
            • 2014-10-20
            • 1970-01-01
            相关资源
            最近更新 更多