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