Rails Nested attributes being duplicated

纵饮孤独 提交于 2019-12-13 07:16:12

问题


This problem has beaten me. I've been at it all weekend but can't figure out what is happening.

When I create a new employee object, I also want to create multiple new ee_pay records using accepts_nested_attributes_for :ee_pay in my employee model.

Creation of ee_pay records for new employees is dependent on the amount of company_pay objects that exist for the company that the employee belongs to. So in the case below there's 2 company_pay objects -> "Basic" [id:2] and "Time + 1/2" [id:3] (returned in the before_action) and I want to create an ee_pay for each of these for the employee in question

Here's the code:-

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

When I go to create a new employee record, I'm getting the following output for the ee_pay objects. It turns out the code is duplicating each one in the following format:-

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

It looks to me like this line @ee_pay_types << @employee.ee_pay.build(company_pay_id: pt.id) in the employees_controller is building two new ee_pay objects (that are output in the debug in the picture above). Then in the view, it's iterating over these two and for each one, creating two new ee_pay objects. I think this is what's happening but I could be completely wring. I'm lost at this stage and I've no idea how to fix it.

Hopefully, someone can point me in the right direction on how to solve it. It's probably something very obvious that I'm missing.

Thanks for looking

Edit 1

Adding the models as requested

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 suggested in the comments changing the employee_controller to this

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

and removing the iteration over @ee_pay_types in the view, which now looks like (I changed any reference to ee_pay to 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> 

But this gives me the error:-

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

To me it looks like I can't access the company_pay of the ee_pay being created. Anyone any ideas?

Edit 2 - Solved

After making the edits suggested by Yan Foto, I was then able to access the company_pay of the ee_pay being created using builder.object.company_pay.description. Thanks again Yan.


回答1:


You don't need to iterate before fields_for since it renders your form for the number of existing associations. You can confirm this by changing the number of @taxable_pays to 3 and see how you get 9 (and not 6) items in your form.

Change your controller to the following:

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

and remove <% @ee_pay_types.each do |ee_pay| %> from your form and you're good to go.

Update You also wanted to access CompanyPay in the form:

builder.object gives you access to the form object (EePay instance) and calling builder.object.company_pay.description gives you the description of the associated CompanyPay.



来源:https://stackoverflow.com/questions/28411934/rails-nested-attributes-being-duplicated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!