嵌套表单,包含simple_form和强参数

时间:2014-03-19 12:37:45

标签: ruby-on-rails strong-parameters

与simple_form的嵌套has_many关联返回以下参数hash:

params
# => {
       "user"=>{
         "first_name"=>"John",
         "last_name"=>"Doe",
         "bank_accounts_attributes"=>{
           "-1"=>{
             "_destroy"=>"0",
             "iban"=>"fakeiban",
             "bic"=>"fakebic"
           },
           "new-bank-account"=>{
             "_destroy"=>"0",
             "iban"=>"",
             "bic"=>""
           }
         }
       }
     }

键“-1”是一个新的,尚未持久化的bank_accout,它是通过复制DOM中的“新银行帐户”模板而创建的(由于iban为空白而被忽略)。

如何将这些参数用于强参数?

我尝试过以下无效:

permitted_params = {
  :first_name,
  :last_name,
  { 
    :bank_accounts_attributes=>[:iban, :bic]
  }
}

params.require(:user).permit(*permitted_params)
Unpermitted parameters: -1, new-bank-account
# => {
       "user"=>{
         "first_name"=>"John",
         "last_name"=>"Doe",
         "bank_accounts_attributes"=>{}
       }
     }

我在这里做错了什么?

更新

以下是有效的,但我不想在任何地方明确地包含否定键(代表无人关系):

params.require(:user).permit(:first_name, :last_name,  bank_accounts_attributes: {"-1" => [:iban, :bic]})

更新2:

问题似乎是“新银行帐户”密钥:

p = ActionController::Parameters.new user: { first_name: "Foo", bank_accounts_attributes: {"-1" => {iban: 'xxx'}, "-2" => {iban: 'yyy'}}}
p.require(:user).permit(:first_name, bank_accounts_attributes: :iban)
# => {"first_name"=>"Foo", "bank_accounts_attributes"=>{"-1"=>{"iban"=>"xxx"}, "-2"=>{"iban"=>"yyy"}}}

p = ActionController::Parameters.new user: { first_name: "Foo", bank_accounts_attributes: {"-1" => {iban: 'xxx'}, "new-bank-account" => {iban: 'yyy'}}}
p.require(:user).permit(:first_name, bank_accounts_attributes: :iban)
# => {"first_name"=>"Foo", "bank_accounts_attributes"=>{}}

看来我必须在提交表单之前从DOM中删除模板“new-bank-account”。

1 个答案:

答案 0 :(得分:0)

我会回答我自己的问题:

强参数只有在它们是整数时才接受has_many键。一个非整数键足以使所有嵌套记录从params散列中消失。因此有两种解决方案:

  • 为模板使用非整数键(例如“new-entry”),并在表单提交之前将其从DOM中删除。
  • 如果你像我一样并且不想要这个额外的JS代码,请为模板使用保留的数字键,例如“999999”,并确保新的,未加载的嵌套记录不会发生冲突。由于持久记录的键是“0”,“1”等,我们使用一个指定“-1”并倒计时的计数器。另一种方法是时间戳,例如Date.now()(快速,但不适用于< = IE8)或+new Date()(速度较慢,但​​适用于IE8)。