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 %>

<h2>Add Projects:</h2>
  <ul id="invoice_items">
    <li class="invoice_item">

      <% 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>
  </ul>
  <%= link_to_new_nested_form "Add a Project", f, :invoice_items %>
  <hr />
  <p>
    <%= f.label :date_due %><br />
    <%= f.date_select :date_due, :default => 15.days.from_now,
                                  :order => [:day, :month, :year],
                                  :start_year => Time.now.year

                                   %>
  </p>
  <p><%= f.submit "Submit" %></p>
<% 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!

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..

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!

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