问题
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