marcel.jira-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2013-Jul-10  22:59 UTC
Nested attributes - not working in forms
Hi!
I also posted this on
railsforum<http://railsforum.com/viewtopic.php?id=56824>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) 
=========================================
Next, I specified the models
# app/models/person.rb
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
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
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
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>
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 %>
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
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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
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.
The fields_for form helper can only loop over association phone numbers 
that exist. The way to have new phone numbers added is to build them in 
advance. E.g.
@person.phones.build
Or if you want to supply 4 phone number fields:
4.times {@person.phone.build}
In that case you should add a reject_if option to your 
accept_nested_attributes :phone statement to have empty left phone numbers 
skipped.
You can build the phone numbers in you controller or use a form_helper like 
setup_person(person) in your forms.
See this Rails Cast: 
http://railscasts.com/episodes/196-nested-model-form-part-1
-- 
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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To view this discussion on the web visit
https://groups.google.com/d/msgid/rubyonrails-talk/402260f2-81f9-41cf-bcf6-8c06c0fd9674%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
marcel.jira-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2013-Jul-13  21:06 UTC
Re: Nested attributes - not working in forms
Thank you, especially for linking the Railcast! Watching this railcast helped me solving tis problem. However, .build is just an alias for .new, which I have already in def new. The problem was about this line in the view: <%= form_for :person, url: people_path do |f| %> It should be <%= form_for @person, url: people_path do |f| %> Am Samstag, 13. Juli 2013 13:35:34 UTC+2 schrieb javinto: instead. Something else: a dedicated form object would be a better practise, right? Is there a detailled instruction on how to make a form object? Or a tutorial on adding classes not connected to ActiveRecords in general? Thank you!> The fields_for form helper can only loop over association phone numbers > that exist. The way to have new phone numbers added is to build them in > advance. E.g. > > @person.phones.build > > Or if you want to supply 4 phone number fields: > > 4.times {@person.phone.build} > > In that case you should add a reject_if option to your > accept_nested_attributes :phone statement to have empty left phone numbers > skipped. > > You can build the phone numbers in you controller or use a form_helper > like setup_person(person) in your forms. > > See this Rails Cast: > http://railscasts.com/episodes/196-nested-model-form-part-1 >-- 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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/ad53f10e-7b81-4f3c-9546-cdd5c6e96091%40googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.