Nested form is giving me the wrong params

I am working on an invoice tracking system for my business and have
gotten so close to getting this portion to work!

I have an Invoice model with many InvoiceItems.

I am following this example (which is based off of ryan daigle’s post)
http://transfs.com/devblog/2009/06/26/nested-forms-with-rails-2-3-helpers-and-javascript-tricks/
and I’ve looked at a couple of other similar examples as well.

I can generate the fields just fine, but when I try to add more fields
and save, I get the following message:

ActiveRecord::UnknownAttributeError in InvoicesController#update

unknown attribute: invoice_items

Parameters:
{“commit”=>“Submit”,
“invoice”=>{“invoice_items_attributes”=>{“1248641854778”=>
{“invoice_items”=>{“project_id”=>“9”,
“_delete”=>“0”,
“amount_billed”=>“48”}},
“0”=>{“project_id”=>“8”,
“_delete”=>“0”,
“id”=>“29”,
“amount_billed”=>“32.00”}},
“date_due(1i)”=>“2009”,
“date_due(2i)”=>“8”,
“date_due(3i)”=>“9”},
“client_id”=>“1”,
“_method”=>“put”,
“authenticity_token”=>“WiwqytxYy/KZSrO76kWKGCH2hMlgiCj1lSedQV3h6KA=”,
“id”=>“17”}

The second line of parameters looks like it goes one level too deep
with the Hash key “invoice_items”. If you go further down to where the
project_id is 8, that is the record that was already in existance.
Below is the yaml output of the request.

Here is the same request converted to yaml:

— !map:HashWithIndifferentAccess
commit: Submit
invoice: !map:HashWithIndifferentAccess
invoice_items_attributes: !map:HashWithIndifferentAccess
“1248641854778”: !map:HashWithIndifferentAccess
invoice_items: !map:HashWithIndifferentAccess
project_id: “9”
_delete: “0”
amount_billed: “48”
“0”: !map:HashWithIndifferentAccess
project_id: “8”
_delete: “0”
id: “29”
amount_billed: “32.00”
date_due(1i): “2009”
date_due(2i): “8”
date_due(3i): “9”
authenticity_token: WiwqytxYy/KZSrO76kWKGCH2hMlgiCj1lSedQV3h6KA=
_method: put
client_id: “1”
action: update
id: “17”
controller: invoices

My form basically looks like this:

<% form_for [@client, @invoice], setup_invoice(@invoice) do |f| %>
<%= f.error_messages %>

Add Projects:

  •   <% f.fields_for :invoice_items do |invoice_item| %>
        <%= invoice_item.collection_select :project_id,
    

    @client.projects, :id, :title, { :include_blank => true } %>
    <%= invoice_item.label :amount_billed, “Amount to bill” %>
    <%= invoice_item.text_field :amount_billed %>

        <% if invoice_item.object.new_record? %>
          <%= link_to_function "clear", "this.up('.invoice_item').remove
    

    ()" %>
    <% else %>
    <%= invoice_item.check_box ‘_delete’ %>
    <%= invoice_item.label ‘_delete’, ‘Remove’ %>
    <% end %>
    <% end %>

    </li>
    
<%= link_to_new_nested_form "Add a Project", f, :invoice_items %>

<%= f.label :date_due %>
<%= f.date_select :date_due, :default => 15.days.from_now, :order => [:day, :month, :year], :start_year => Time.now.year

                               %>

<%= f.submit "Submit" %>

<% end %>

I’m just not sure how to change the code to make it work!

Here is what I have in my application_helper.rb:

def generate_html(form_builder, method, options = {})
options[:object] ||=
form_builder.object.class.reflect_on_association(method).klass.new
options[:partial] ||= method.to_s.singularize
options[:form_builder_local] ||= :f
form_builder.fields_for(method, options[:object], :child_index =>
‘NEW_RECORD’) do |f|
render(:partial => options[:partial], :locals => { options
[:form_builder_local] => f })
end
end

def link_to_new_nested_form(name, form_builder, method, options =
{})
options[:object] ||=
form_builder.object.class.reflect_on_association(method).klass.new
options[:partial] ||= method.to_s.singularize
options[:form_builder_local] ||= :f
options[:element_id] ||= method.to_s
options[:position] ||= :bottom
link_to_function name do |page|
html = generate_html(form_builder,
method,
:object => options[:object],
:partial => options[:partial],
:form_builder_local => options
[:form_builder_local]
)
page << %{
$(‘#{options[:element_id]}’).insert({ #{options
[:position]}: “#{ escape_javascript html }”.replace(/NEW_RECORD/g, new
Date().getTime()) });
}
end
end

I’ve had other problems with this approach as well, but if I can at
least get it to save to the db I should be okay.

Three things I can offer advice on here. You seem to be like me in you
post a lot of information…

So, first post all that code on pastie.org or gisthub so it’s ordered
nicely and easy to view. Then, post the link back here.

Second, you ran a <%= debug(params) %> in your view to verify all
parameters?

Third, your field does exist in the table you are querying?

If all those checks out, I’ll see if i can see anything on your new view
code. Four eyes are better than 2. :slight_smile:

First of all, thanks for taking the time to recommend a better way of
displaying my problem!

Here is the gist http://gist.github.com/155971

The problem arises when I use the helper method in my
application_helper.rb to create new fields for the nested form.

In my controller I build one instance of the invoice_item
(@invoice.invoice_items.build) and that field works just fine, when
viewing the parameters, it is the section that reads:

“0”: !map:HashWithIndifferentAccess
project_id: “8”
_delete: “0”
id: “31”
amount_billed: “32.00”

It is the one above (in the params from the gist) that that looks
similar (project_id: 9, amount_billed: “68”) that is the problem, it
is getting nested too deep under “invoice_items”…unnecessarily so it
would seem. I have added my Invoice and InvoiceItems models to the
gist as well.

Thanks for your help!

On Jul 26, 3:10 pm, Alpha B. [email protected]

I’m not saving anything before the new nested instance is created. I
didn’t write the piece using :child_index, but perhaps I should do
some more research about that chunk of code. Thanks again for your
help, I’ll try to post the solution when I find it!

On Jul 26, 6:17 pm, Alpha B. [email protected]

Yet another stupid mistake. I wasn’t keeping track of my partials and
I had nested my nested form, thus creating the extra level of params.
Sheesh

Hi Matt,

Well the code checks out fine from my end with regards to syntax.
However, I have a question in regards to your invoice…

Are you saving anything at all before the new nested instance is
created? The reason I ask is because you are using :child_index and I
was just curious whether you would run into issues with unused
instances, or perhaps the issue is somewhere in that piece?

Other than that, I just don’t know mate…