Rails 4嵌套属性哈希键显示为未允许

时间:2015-02-25 22:15:17

标签: ruby-on-rails ruby-on-rails-4 nested-attributes

我有Category模型和Standard模型。一个类别通过“连接表”模型CategoryStandard有许多标准。在我看来,我有一个表单,我可以编辑类别描述,然后添加或删除该类别的标准。所以,我的嵌套属性适用于:category_standards,因为我没有编辑标准本身,只是添加或删除关系,如果这是有意义的。

以下是该观点的重要部分:

<%= form_for(@category) do |f| %>
...
  <div class="field">
    <%= f.label :description %>
    <%= f.text_field :description %>
  </div>

  <%= label_tag nil, "Standards in this Category" %>
  <div id="standard-list">
    <%= f.fields_for :category_standards do |ff| %>
      <div class="field">
        <%= ff.object.standard.number_with_exceptions %>
        <%= ff.hidden_field :standard_id %>
        <%= ff.hidden_field :_destroy %>
        <%= link_to "<span class='glyphicon glyphicon-remove'></span>".html_safe, "", class: "del-std-btn", title: "Remove standard from category" %>
      </div>
    <% end %>

    <div class="hidden" id="std-add-new-template">
      <div class="field">
        <%= f.fields_for :category_standards, CategoryStandard.new, child_index: "new_id" do |ff| %>
          <%= ff.collection_select :standard_id, @standards - @category.standards, :id, :number_with_exceptions, prompt: "Select a standard to add" %>
        <% end %>
      </div>
    </div>
  </div>
...
<% end %>

有一些jQuery来操纵“行”,但是工作正常,我不认为这是我问题的一部分,所以我会省略它。

在我的分类模型中,我有:

class Category < ActiveRecord::Base
  has_many :category_standards, dependent: :destroy
  has_many :standards, through: :category_standards
  validates :description, presence: true,
                          uniqueness: true
  accepts_nested_attributes_for :category_standards, allow_destroy: true, reject_if: proc { |attributes| attributes['standard_id'].blank?}
end

在我的分类控制器中,我有:

def category_params
  params.require(:category).permit(:description, category_standards_attributes: [:id, :standard_id, :_destroy])
end

但是当我尝试将标准添加到某个类别时,我会在服务器日志中添加这些行(为了使其更具可读性而重新格式化):

Parameters: {"utf8"=>"✓",
              "authenticity_token"=>"***********",
              "category"=>{
                "description"=>"Drinking Water System Components", 
                "category_standards_attributes"=>{
                  "0"=>{
                    "standard_id"=>"2",
                    "_destroy"=>"false",
                    "id"=>"1"
                  }, 
                  "new_id"=>{
                    "standard_id"=>""
                  },
                  "1424899001814"=>{
                    "standard_id"=>"1"
                  }
                }
              },
              "commit"=>"Save Changes",
              "id"=>"2"
            }

User Load (5.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1

Category Load (4.0ms)  SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT 1  [["id", "2"]]

Unpermitted parameters: 0, new_id, 1424899001814

(4.0ms)  BEGIN
Category Exists (6.0ms)  SELECT 1 AS one FROM "categories" WHERE ("categories"."description" = 'Drinking Water System Components' AND "categories"."id" != 2) LIMIT 1

SQL (6.0ms)  UPDATE "categories" SET "description" = $1, "updated_at" = $2 WHERE "categories"."id" = 2  [["description", "Drinking Water System Components"], ["updated_at", Wed, 25 Feb 2015 21:16:44 UTC +00:00]]

它更新了描述字段,但是未经许可的参数是什么?我的属性哈希就像nested forms上的Rails指南中的示例一样,它甚至说:“addresses_attributes哈希的键是不重要的,它们只需要对每个地址都不同。”然而,这是被我拒绝的钥匙。

我哪里出错了?谢谢!

2 个答案:

答案 0 :(得分:1)

经过大量阅读后想出来了。缺失的部分是here

  

具有整数键的哈希值的处理方式不同,您可以将属性声明为直接子项。当您将accepts_nested_attributes_for与has_many关联结合使用时,您会获得以下类型的参数:

# To whitelist the following data:
# {"book" => {"title" => "Some Book",
#             "chapters_attributes" => { "1" => {"title" => "First Chapter"},
#                                        "2" => {"title" => "Second Chapter"}}}}

params.require(:book).permit(:title, chapters_attributes: [:title])

其中重要的部分是“具有整数键的哈希”。我的哈希键传递为“0”,“new_id”,“1240934304343”。使用“new_id”并不重要,因为这只是一个占位符值,当我添加新行时,我的jQuery会改变它。只有模板行保留该值,这很好,因为它被我的reject_if子句过滤掉了。

但是“new_id”不是整数的事实显然是把它全部搞砸了。所以我把它改为“-1”,Rails接受了(即使它仍被reject_if过滤掉了,因为它应该是)。

<div class="hidden" id="std-add-new-template">
  <div class="field">
    <%= f.fields_for :category_standards, CategoryStandard.new, child_index: "-1" do |ff| %>
      <%= ff.collection_select :standard_id, @standards - @category.standards, :id, :number_with_exceptions, prompt: "Select a standard to add" %>
    <% end %>
  </div>
</div>

答案 1 :(得分:0)

您的属性键似乎与您在强参数中的预期不符,“new_id”和“1424899001814”肯定不会被允许。

"new_id"=>{
    "standard_id"=>""
},
"1424899001814"=>{
    "standard_id"=>"1"
}

我怀疑你构建表单的方式无效。尝试将其分解为最简单的工作形式..例如:

    <div id="standard-list">
        <%= link_to "<span class='glyphicon glyphicon-remove'></span>".html_safe, "", class: "del-std-btn", title: "Remove standard from category" %>

        <div class="hidden" id="std-add-new-template">
          <div class="field">
            <%= f.fields_for :category_standards do |ff| %>
                <%= ff.object.standard.number_with_exceptions %>
                <%= ff.hidden_field :standard_id %>
                <%= ff.hidden_field :_destroy %>
                <%= ff.collection_select :standard_id, @standards - @category.standards, :id, :number_with_exceptions, prompt: "Select a standard to add" %>
            <% end %>
          </div>
        </div>
    </div>

目的是只有一个嵌套的表单,通过剥离它只创建一个嵌套的哈希。

"category_standards_attributes"=>{
    "0"=>{
        "standard_id"=>"2",
        "_destroy"=>"false",
        "id"=>"1"
    }
}

这会发生什么?