[Rails] Nested attributes - not working in forms
Hi!
I also posted this on railsforum but then I realized this is probably not the best place to get answers for this problem. So, sorry for this crosspost...
I also want to apologize for this long message. I just wanted to provide all information - on the one hand to make the error reproducable, on the other hand to enable people who maybe have the same problem in the future to get step-by-step instructions.
I try to generate a form with an 1:many-model. Doing so, I found the command accepts_nested_attributes_for. However, in my form only the parent-model gets saved, while the child-model stays empty.
I started by creating a project (I called it PhoneBook) in Rails 4.
Then I generated two models and started the migration:
$ rails g model person name
invoke active_record
create db/migrate/20130710205309_create_people.rb
create app/models/person.rb
invoke test_unit
create test/models/person_test.rb
create test/fixtures/people.yml
$ rails g model phone person_id:integer phone_number:integer
invoke active_record
create db/migrate/20130710205415_create_phones.rb
create app/models/phone.rb
invoke test_unit
create test/models/phone_test.rb
create test/fixtures/phones.yml
$ rake db:migrate
== CreatePeople: migrating ===================================================
-- create_table(:people)
-> 0.0008s
== CreatePeople: migrated (0.0008s) ==========================================
== CreatePhones: migrating ===================================================
-- create_table(:phones)
-> 0.0007s
== CreatePhones: migrated (0.0008s) ==========================================
invoke active_record
create db/migrate/20130710205309_create_people.rb
create app/models/person.rb
invoke test_unit
create test/models/person_test.rb
create test/fixtures/people.yml
$ rails g model phone person_id:integer phone_number:integer
invoke active_record
create db/migrate/20130710205415_create_phones.rb
create app/models/phone.rb
invoke test_unit
create test/models/phone_test.rb
create test/fixtures/phones.yml
$ rake db:migrate
== CreatePeople: migrating ===================================================
-- create_table(:people)
-> 0.0008s
== CreatePeople: migrated (0.0008s) ==========================================
== CreatePhones: migrating ===================================================
-- create_table(:phones)
-> 0.0007s
== CreatePhones: migrated (0.0008s) ==========================================
Next, I specified the models
# app/models/person.rb
class Person < ActiveRecord::Base
has_many :phones
accepts_nested_attributes_for :phones
end
class Person < ActiveRecord::Base
has_many :phones
accepts_nested_attributes_for :phones
end
# app/models/phone.rb
class Phone < ActiveRecord::Base
belongs_to :person
end
class Phone < ActiveRecord::Base
belongs_to :person
end
Then I created a controller for person
$ rails g controller people
create app/controllers/people_controller.rb
invoke erb
create app/views/people
invoke test_unit
create test/controllers/people_controller_test.rb
invoke helper
create app/helpers/people_helper.rb
invoke test_unit
create test/helpers/people_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/people.js.coffee
invoke scss
create app/assets/stylesheets/people.css.scss
create app/controllers/people_controller.rb
invoke erb
create app/views/people
invoke test_unit
create test/controllers/people_controller_test.rb
invoke helper
create app/helpers/people_helper.rb
invoke test_unit
create test/helpers/people_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/people.js.coffee
invoke scss
create app/assets/stylesheets/people.css.scss
This controller was filled with the following code
class PeopleController < ApplicationController
def new
@person = Person.new
@person.phones.new
end
def create
@person = Person.new(person_params)
@person.save
redirect_to people_path
end
def index
@person = Person.all
end
private
def person_params
params.require(:person).permit(:name, phone_attributes: [ :id, :phone_number ])
end
end
def new
@person = Person.new
@person.phones.new
end
def create
@person = Person.new(person_params)
@person.save
redirect_to people_path
end
def index
@person = Person.all
end
private
def person_params
params.require(:person).permit(:name, phone_attributes: [ :id, :phone_number ])
end
end
Of course I also needed some views. This one just shows the list of all people with their phone numbers
<h1>Phone Book</h1>
<ul>
<% @person.each do |person| %>
<li>
<h2>
<%= person.name %>
</h2>
<ul>
<% person.phones.each do |phone| %>
<li>
<%= phone.phone_number %>
</li>
<% end %>
</ul>
</li>
<% end %>
</ul>
<ul>
<% @person.each do |person| %>
<li>
<h2>
<%= person.name %>
</h2>
<ul>
<% person.phones.each do |phone| %>
<li>
<%= phone.phone_number %>
</li>
<% end %>
</ul>
</li>
<% end %>
</ul>
and this one is the interesting part: here's my code for the form that should create new people and phone numbers:
<%= form_for :person, url: people_path do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :phones do |f_phone| %>
<div class="field">
<p>
<%= f_phone.label :phone_number %><br />
<%= f_phone.text_field :phone_number %>
</p>
</div>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :phones do |f_phone| %>
<div class="field">
<p>
<%= f_phone.label :phone_number %><br />
<%= f_phone.text_field :phone_number %>
</p>
</div>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
To make it work (well it doesn't work, but almost) I also need a route of course:
PhoneBook::Application.routes.draw do
resources :people
end
resources :people
end
Are you still with me? Great! Creating a new person with a phone number in the rails console works without any problems. However, when I try my form, only the Person gets stored, while the phone number is lost.
Can you help me with this problem? What am I doing wrong?
Do I maybe need a controller for phone_number? As it is only accessed via person, I thought I wouldn't need one.
Thank you in advance!
--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe@googlegroups.com.
To post to this group, send email to rubyonrails-talk@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/21e6a795-7d5e-4537-b3e4-424be6c4bd7c%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home