Reputation: 247
I'm using Rails 2.3.2, and trying to get a nested object form to work properly. I've narrowed my problem to the issue that Rails is not setting my nested form elements with the *_attributes required to initiate the accepts_nested_attributes_for processing.
My model code is:
class Person < Party
has_one :name, :class_name => "PersonName"
accepts_nested_attributes_for :name, :allow_destroy => true
end
class PersonName < ActiveRecord::Base
belongs_to :person
end
My view code looks like this (I'm using HAML):
%h3 New customer
= error_messages_for :person, :person_name, :name, :country
- form_for :person, :url => collection_url, :html => {:class => 'MainForm'} do |person_form|
- @person.build_name unless @person.name
- person_form.fields_for :name do |name_form|
= name_form.label :given_name, "First Name:"
= name_form.text_field :given_name
= name_form.label :family_name, "Last Name:"
= name_form.text_field :family_name
= hidden_field_tag :inviter_id, params[:inviter_id]
= hidden_field_tag :inviter_code, params[:inviter_code]
%p= submit_tag "Create"
= link_to 'Back', collection_url
Instead of params being:
{"person"=>{"name_attributes"=>{"given_name"=>"Fred", "family_name"=>"Flintstone"}}, ...}
I get:
{"person"=>{"name"=>{"given_name"=>"Fred", "family_name"=>"Flintstone"}}, ...}
As a result, I get a TypeMismatch exception. I've followed the documentation from Ryan Daigle. I've also followed the advice from this blog and the complex-forms-example.
Using Firebug, I went through my form and adjusted the name attribute of the input tags from name to name_attributes. This produced the params with name_attributes, and the create worked fine.
I'm stuck as I cannot figure out why my form is not producing the *_attributes form of the name.
Another thing I tried is I got the complex_form_example working in my environment. I've gone through every inch of the controller, models and views and compared it to my code. I cannot find what is different. I know this is something small, and would appreciate any help!
Thanks!
Upvotes: 6
Views: 7140
Reputation: 1064
Thought I would share my solution as it's slightly different - in my case I want the nested attributes to be dynamic.
In new action:
case params[:type]
when "clubber"
@account = resource.send "build_#{params[:type]}"
when "promoter"
@account = resource.send "build_#{params[:type]}"
when "company"
@account = resource.send "build_#{params[:type]}"
when "venue_owner"
flash[:notice] = 'We ask that venue owners register via the web. Thanks.'
redirect_to root_path and return
end
In my view:
= f.fields_for @account.class.name.downcase+'_attributes' do |form|
Pretty ghetto, but it works.
Upvotes: 0
Reputation: 5058
I have just been struggling for about an hour with exactly the same problem!
Follow nowk's pattern for the new method in the controller, then put this in your view
<% form.fields_for :name, @person.name do |name_form| %>
<% end %>
Good luck if you try it, that's what worked for me.
Upvotes: 1
Reputation: 33161
Post backs do not get routed to the right place
def new
@person = Person.new
end
<% form_for @person do |f| %>
<% f.fields_for :name_attributes do |p| %>
...
<% end %>
<% end %>
Post backs get routed to the right place
def new
@person = Person.new
@person.name = PersonName.new # << this allows fields_for :relation vs :relation_attributes
end
<% form_for @person do |f| %>
<% f.fields_for :name do |p| %>
...
<% end %>
<% end %>
No need to @person.name again in #create
Upvotes: 4
Reputation: 21038
Try to use an actual object for form_for:
form_for :person => form_for @person
Upvotes: 4
Reputation: 247
Unfortunately, I still have not been able to figure out why this form wouldn't work with nested object forms. I stripped it down to the simplest data, started over using the complex-form-example as a start. I ended using the active_presenter to gather x-object data from the form. I'll revisit nested object forms sometime in the form. Thanks for your help.
Upvotes: 0
Reputation: 2072
Not sure why this isn't working for, but as a workaround, you could just use params[:name] in your controller#create method to update the person record.
person = Person.new(params[:person])
person.name << PersonName.new(params[:name])
Upvotes: 0