Rails 嵌套属性被复制

Rails Nested attributes being duplicated

这个问题难倒了我。我整个周末都在看它,但不知道发生了什么。

当我创建一个新的 employee 对象时,我还想在我的 employee 模型中使用 accepts_nested_attributes_for :ee_pay 创建多个新的 ee_pay 记录。

为新员工创建 ee_pay 记录取决于员工所属公司存在的 company_pay 个对象的数量。因此,在下面的情况下,有 2 个 company_pay 对象 -> "Basic" [id:2] 和 "Time + 1/2" [id:3](在 before_action 中返回),我想为有问题的员工

为每个人创建一个 ee_pay

代码如下:-

employees_controller.rb

 before_action :set_company_pay_types, only: [:new, :update, :edit]

        def new
            @ee_pay_types = []
            @taxable_pays.each do |pt|
              @ee_pay_types << @employee.ee_pay.build(company_pay_id: pt.id)
            end
        end                 

        private
          def set_company_pay_types
              @taxable_pays = CompanyPay.where(['company_id = ? AND pay_sub_head_id = ? AND description <> ?', current_company.id, 1, "Salary"]).order(:id)
          end

          def employee_params
            params.require(:employee).permit(....[multiple other fields]..., address_attributes:[:id, :line1, :line2, :line3, :line4, :postcode, :country], ee_pay_attributes:[:id, :employee_id, :company_pay_id, :amount, :rate])
          end

views/employees/_form

<div><strong>Hourly Pay Types</strong></div>
<div class="form_spacer"></div>
<div class="row">
   <div class="col-md-3">  
      <div class="form_indent1"><div class="form_label"><strong>Description</strong></div></div>           
   </div> 
   <div class="col-md-3">  
      <div class="form_indent1"><div class="form_label"><strong>Amount</strong></div></div>           
   </div>
   <div class="col-md-2">  
      <div class="form_indent1"><div class="form_label"><strong>Units</strong></div></div>           
   </div>                
   <div class="col-md-4">  
      <div class="form_indent1"><div class="form_label"><strong>Rate</strong></div></div>           
   </div> 
   <div>
             <%= debug @ee_pay_types %> 
             <% @ee_pay_types.each do |ee_pay| %>
                 <%= f.fields_for :ee_pay do |builder| %>                                   
                 <%= builder.hidden_field :company_pay_id %>     
                 <div class="col-md-3">
                     <div class="form_indent1"><div class="form_indent1"><%= ee_pay.company_pay.description %></div></div>
                     <div class="form_spacer"></div>
                 </div> 
                 <div class="col-md-3">
                     <div class="form_indent1"><%= builder.text_field :amount, class: "number_input" %></div>
                     <div class="form_spacer"></div>
                 </div>  
                 <div class="col-md-2">
                     <div class="form_indent1"><%= ee_pay.company_pay.units %></div>
                     <div class="form_spacer"></div>
                 </div>  
                 <div class="col-md-4">  
                     <div class="form_indent1"><%= builder.text_field :rate, class: "number_input" %></div>
                     <div class="form_spacer"></div><br />
                 </div>                             

                 <% end %> 
             <% end %> 
   </div> 
   </div>

Output from employees/new

当我去创建一个新的员工记录时,我得到了 ee_pay 对象的以下输出。事实证明,代码正在按照以下格式复制每个代码:-

*description*        *company_pay_id*    
Basic                   2
Basic                   3
Time & 1/2              2
Time & 1/2              3

在我看来 employees_controller 中的这一行 @ee_pay_types << @employee.ee_pay.build(company_pay_id: pt.id) 正在构建两个新的 ee_pay 对象(在上图中的调试中输出)。然后在视图中,它迭代这两个对象并为每个对象创建两个新的 ee_pay 对象。我认为这就是正在发生的事情,但我可能会完全绞尽脑汁。我在这个阶段迷路了,我不知道如何解决它。

希望有人能为我指出正确的解决方法。这可能是我遗漏的很明显的东西。

感谢观看

Edit 1

按要求添加模型

models/ee_pay

    class EePay < ActiveRecord::Base
        belongs_to :employee
        belongs_to :company_pay
    end

model/company_pay

    class CompanyPay < ActiveRecord::Base
        belongs_to :pay_sub_head
        belongs_to :company
        has_many :ee_pay
    end

model/employee

    class Employee < ActiveRecord::Base
        belongs_to :company
        belongs_to :address
        accepts_nested_attributes_for :address
        has_many :ee_pay
        accepts_nested_attributes_for :ee_pay
    end

Yann 在评论中建议将 employee_controller 更改为此

    @ee_pay_types = []
    @taxable_pays.each do |pt|
        @employee.ee_pay.build(company_pay_id: pt.id)
    end

并删除视图中 @ee_pay_types 的迭代,现在看起来像(我将对 ee_pay 的任何引用更改为 builder):-

    <div>
            <%= debug @ee_pay_types %>  
            <%= f.fields_for :ee_pay do |builder| %>                                    
                <%= builder.hidden_field :company_pay_id %>     

                <div class="col-md-3">
                    <div class="form_indent1"><div class="form_indent1"><%= builder.company_pay.description %></div></div>
                    <div class="form_spacer"></div>
                </div> 
                    <div class="col-md-3">
                    <div class="form_indent1"><%= builder.text_field :amount, class: "number_input" %></div>
                    <div class="form_spacer"></div>
                </div>  
                    <div class="col-md-2">
                    <div class="form_indent1"><%= builder.company_pay.units %></div>
                    <div class="form_spacer"></div>
                </div>  
                    <div class="col-md-4">  
                    <div class="form_indent1"><%= builder.text_field :rate, class: "number_input" %></div>
                    <div class="form_spacer"></div><br />
                </div>
            <% end %> 
    </div> 

但这给了我错误:-

undefined method `company_pay' for #<ActionView::Helpers::FormBuilder:0x007f47d5649118>

对我来说,我似乎无法访问正在创建的 ee_paycompany_pay。有人有什么想法吗?

Edit 2 - Solved

按照 Yan Foto 的建议进行编辑后,我可以访问使用 builder.object.company_pay.description 创建的 ee_paycompany_pay。再次感谢颜

您不需要在 fields_for 之前进行迭代,因为它会根据现有关联的数量呈现您的表单。您可以通过将 @taxable_pays 的数量更改为 3 来确认这一点,并查看您如何在表单中获得 9(而不是 6)项。

将您的控制器更改为以下内容:

def new
  @ee_pay_types = []
  @taxable_pays.each do |pt|
    @employee.ee_pay.build(company_pay_id: pt.id)
  end
end

并从您的表单中删除 <% @ee_pay_types.each do |ee_pay| %>,您就可以开始了。

更新 您还想以以下形式访问 CompanyPay

builder.object 使您可以访问表单对象(EePay 实例)并调用 builder.object.company_pay.description 为您提供关联的 CompanyPay.

的描述