Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails fields_for and nested attributes

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:

  1. address form shown, why can not save to database?

  2. 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:

  1. has_one relation does not support person.address.create. That's only for has_many
  2. rails api for fields_for, is really not clear. It's just missing the whole controller part. Follow it will not make it.
like image 297
ken Avatar asked May 24 '26 00:05

ken


1 Answers

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
like image 102
cschroed Avatar answered May 25 '26 13:05

cschroed



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!