rails fields_for and nested attributes

ruby, ruby-on-rails, ruby-on-rails-4

Solution

Try:

jack = Person.create(name: 'Jack')
jack.create_address(street: '12w 33st')

When there is only one associated address (`has_one :address`) you use `create_address`. When there are many associated addresses (`has_many :addresses`) you use `addresses.create`.

Also, in your view you will want `f.fields_for` instead of `fields_for`.

I would recommend checking out the RailsCasts for Nested Model Form to learn more.

Additional Info (to address comments below)

Also note that `create` will make a new object and attempt to save it in the database. `build` will just build the new object. In your PeopleController you'll want something like this:

def new
  @person = Person.new
  @person.build_address
end

Based on your need, you can determine whether you want this `build` to occur in other actions or in callbacks in the model. But this will get you started.

You'll also need to update the `person_params` to

def person_params
  params.require(:person).permit(:name, :age, :gender, address_attributes: [:id, :street, :zip_code])
end

Problem

I have difficulty to understand how to use fields_for and nested attributes. In order to understand it better, I created a repo, which is not working. I read this, which is not helpful. I am using: Rails 4.0.1 Ruby 2.0.0-p247 Question: address form shown, why can not save to database? Why not work? `jack = Person.create(name: 'Jack')` `jack.address.create(street: '12w 33st') ` The main function is as below: ``` #model class Person < ActiveRecord::Base has_one :address accepts_nested_attributes_for :address end class Address < ActiveRecord::Base belongs_to :person end ``` view as below: ``` <%= form_for(@person) do |f| %> <% if @person.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@person.errors.count, "error") %> prohibited this person from being saved:</h2> <ul> <% @person.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :name %><br> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :age %><br> <%= f.text_field :age %> </div> <div class="field"> <%= f.label :gender %><br> <%= f.text_field :gender %> </div> <%= fields_for :address do |address_fields|%> Street: <%= address_fields.text_field :street%> Zip code: <%= address_fields.text_field :zip_code%> <% end %> <div class="actions"> <%= f.submit %> </div> <% end %> ``` nested attributes Conclusion: - has_one relation does not support `person.address.create`. That's only for has_many - rails api for `fields_for`, is really not clear. It's just missing the whole controller part. Follow it will not make it.

Original source