Al D
Al D

Reputation: 667

Rails creating multiple records in nested form

I've been at this for hours now but can't find a solution and am now wondering if I'm approaching this correctly.

I have an employee form and in it I'm creating multiple ee_pay records (which store a reference to the company_pay type they are). The problem is accessing the company_pay associated with the ee_pay that I'm creating in the form.

The code below works but I keep getting the description of the second @taxable_pays type in the variable @description in _pay_types.html.erb

I'm not entirely sure why this is happening. I've tried multiple ways of passing the description of each one. I know there's two in that collection because the correct ids are getting stored in two separate ee_pay records that get saved when I submit the form.

Can anyone tell me how I can pass the value of each @taxable_pays.description to the view? And also tell me if I'm approaching this in the best way?

Thanks for looking. Here's my code:

employees_controller.rb

I have a before_action that does the following:

@taxable_pays = CompanyPay.where(company_id: current_company.id).order(:id)

Then:

  def new
    @taxable_pays.each do |pt|
    pay_type = @employee.ee_pay.build(company_pay_id: pt.id)
    @description = pt.description
  end

_form.html.erb

      <div class="row">
          <div class="col-md-4">  
            <div class="form_label"><strong>Description</strong></div>           
          </div> 
          <div class="col-md-4">  
            <div class="form_label"><strong>Amount</strong></div>           
          </div> 
          <div class="col-md-4">  
            <div class="form_label"><strong>Rate</strong></div>           
          </div> 

            <%= f.fields_for :ee_pay do |builder| %>
              <%= render "pay_types", :f => builder %>              
            <% end %>                 

      </div>  

_pay_types.html.erb

  <div class="col-md-4">
    <div class="form_indent1"><div class="form_indent1"><%= @description %></div></div>
    <div class="form_spacer"></div>
  </div> 
  <div class="col-md-4">
    <div class="form_indent1"><%= f.text_field :amount, class: "number_input" %></div>
    <div class="form_spacer"></div>
  </div>  
  <div class="col-md-4">  
    <div class="form_indent1"><%= f.text_field :rate, class: "number_input" %></div>
    <div class="form_spacer"></div><br />
  </div>

Edit 1 (updated)

After advice from Mark G. below my code now looks like:-

employees_controller.rb

  @pay_types = []
  @taxable_pays.each do |pt|
    @pay_types << @employee.ee_pay.build(company_pay_id: pt.id)
    puts "Debug for the pay_types"
    puts @pay_types
  end

_form.html.erb

    <div>
      <% @pay_types.each do |ee_pay| %>
        <%= f.fields_for :ee_pay do |builder| %>
          <%= render "pay_types", :f => builder, :ee_pay => ee_pay %>              
        <% end %>                 
      <% end %> 
    </div>

_pay_types.html.erb

    <%= f.hidden_field :company_pay_id %>  (not on original edit)

    <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"><%= f.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"><%= f.text_field :rate, class: "number_input" %></div>
      <div class="form_spacer"></div><br />
    </div>

I originally thought this was each of the @pay_types printing twice but looking at it again it's the description printing twice, each time with each of the company_pay_ids

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

I'm really stumped with this.

Edit 2

This is the console output I'm getting when I try create a new employee

        CompanyPay Load (0.7ms)  SELECT  "company_pays".* FROM "company_pays"  WHERE "company_pays"."id" = $1 LIMIT 1  [["id", 2]]
          Rendered employees/_pay_types.html.erb (2.8ms)
        Debug in the _form view fields_for
        #<EePay:0x007f4130a214a8>
          Rendered employees/_pay_types.html.erb (0.5ms)
        Debug in the _form view fields_for
        #<EePay:0x007f4130a214a8>
          CompanyPay Load (0.8ms)  SELECT  "company_pays".* FROM "company_pays"  WHERE "company_pays"."id" = $1 LIMIT 1  [["id", 8]]
          Rendered employees/_pay_types.html.erb (2.4ms)
        Debug in the _form view fields_for
        #<EePay:0x007f4130a1fcc0>
          Rendered employees/_pay_types.html.erb (0.7ms)
        Debug in the _form view fields_for
        #<EePay:0x007f4130a1fcc0>
          Rendered employees/_form.html.erb (37.5ms)
          Rendered employees/new.html.erb within layouts/application (38.3ms)

I'm giving up for the night. Been looking at it for too long and getting nowhere. Thanks for the help. Will try again tomorrow

Upvotes: 0

Views: 1030

Answers (2)

Al D
Al D

Reputation: 667

I went around in circles with this using Mark's method so asked another question on stackoverflow which can be found here. This might help someone else who lands here.

Basically, the code should be:-

employees_controller

@taxable_pays.each do |tp|
  @employee.ee_pay.build(company_pay_id: tp.id)
end

_form

<%= f.fields_for :ee_pay do |builder| %>
   <%= render "pay_types", :f => builder %>    
<% end %> 

_pay_types

    <div class="row">
        <%= f.hidden_field :company_pay_id %> 
        <div class="col-md-2">
          <div class="form_indent1"><div class="form_indent1"><%= f.object.company_pay.description %></div></div>
          <div class="form_spacer"></div>
        </div> 
        <div class="col-md-10">         
            <div class="col-md-4">  
              <div class="form_indent1"><%= f.text_field :rate, class: "number_input" %></div>
              <div class="form_spacer"></div><br />
            </div>
            <div class="col-md-4">
              <div class="form_indent1"><%= f.text_field :amount, class: "number_input" %></div>
              <div class="form_spacer"></div>
            </div>  
        </div>  
    </div>

Notice how in the _pay_types partial, the company_pay associated with the ee_pay being built can be accessed using <%= f.object.company_pay.description %>, as long as all the associations are set up correctly. So simple.

Upvotes: 0

Mark G.
Mark G.

Reputation: 3280

In the example code you gave above, @description is an instance variable on your controller. It looks like you're iterating over all your @taxable_pays objects and assigning @description within that loop, so the value of @description is always going to be whatever the last taxable pay's description is.

Conceptually, it looks like you're trying to do the right thing, but I think you might be making it more complicated than it needs to be. It looks like ee_pay is associated to CompanyPay right? Why not in your _pay_types.html.erb file, just go through the association that you've established?

<div class="form_indent1"><%= ee_pay.company_pay.description %></div>

Since you don't have the ee_pay variable available to your partial, you'll need to pass that to your partial in _form.html.erb. Also, how are you generating multiple sets of form fields without looping over the ee_pay collection? I would picture it working something like (naming seems a bit confusing, but just going with what you had):

controller

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

_form.html.erb

<% @pay_types.each do |ee_pay| %>
  <%= f.fields_for :ee_pay do |builder| %>
    <%= render "pay_types", :f => builder, :ee_pay => ee_pay %>              
  <% end %> 
<% end %>

Let me know if that doesn't work and we can tweak things until you get something that solves your particular problem.

Upvotes: 1

Related Questions