3

I have the following models defined in my application

  • User
  • Profile
  • Address

Here is my user model:

class User < ActiveRecord::Base

  # Include default devise modules. Others available are:
  # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_attributes

  has_one :profile
  accepts_nested_attributes_for :profile
end

Here is my profile model:

class Profile < ActiveRecord::Base

  attr_accessible :first_name, :last_name, :organization, :telephone_number, :user_id, :address_attributes

  belongs_to :user
  has_one :address

  accepts_nested_attributes_for :address
end

Here is my address model:

class Address < ActiveRecord::Base
  attr_accessible :street, :street_cont, :city, :state, :zip_code
  belongs_to :profile
end

I am using devise for authentication so in my view I have the following for registration:

<% resource.build_profile %>
<h2>Sign up</h2>

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <p><%= f.label :email %><br />
  <%= f.email_field :email %></p>

  <p><%= f.label :password %><br />
  <%= f.password_field :password %></p>

  <p><%= f.label :password_confirmation %><br />
  <%= f.password_field :password_confirmation %></p>

  <%=f.fields_for :profile do |profile_form| %>
      <p><%= profile_form.label :first_name %><br />
      <%= profile_form.text_field :first_name %></p>

      <p><%= profile_form.label :last_name %><br />
      <%= profile_form.text_field :last_name %></p>

      <p><%= profile_form.label :organization %><br />
      <%= profile_form.text_field :organization %></p>

      <p><%= profile_form.label :telephone_number %><br />
      <%= profile_form.text_field :telephone_number %></p>

      <%=f.fields_for :address do |address_form| %>
        <p><%= address_form.label :street %><br />
        <%= address_form.text_field :street %></p>

        <p><%= address_form.label :street_cont %><br />
        <%= address_form.text_field :street_cont %></p>

        <p><%= address_form.label :city %><br />
        <%= address_form.text_field :city %></p>

        <p><%= address_form.label :state %><br />
        <%= address_form.text_field :state %></p>

        <p><%= address_form.label :zip_code %><br />
        <%= address_form.text_field :zip_code %></p>
     <% end %>
  <% end %>

  <p><%= f.submit "Sign up" %></p>
<% end %>

<%= render :partial => "devise/shared/links" %>

The form renders correctly but when I view the source I see this for the address fields:

<input id="user_address_street" name="user[address][street]" size="30" type="text" />

for the profile section I see:

<input id="user_profile_attributes_first_name" name="user[profile_attributes][first_name]" size="30" type="text" />

When I save the form, the user and profile are saved to the database but not the address. I'm obviously doing something wrong possibly with my model relationships but I don't know how to go about solving this.

Any help would be appreciated.

Mike
  • 2,561
  • 7
  • 34
  • 56
  • Why are you using nested HTML forms? I believe that is logically incorrect if not also functionally incorrect. see http://stackoverflow.com/questions/379610/can-you-nest-html-forms – Gal May 11 '11 at 19:27

1 Answers1

3

Change this:

 <%=f.fields_for :address do |address_form| %>

To this:

<%=profile_form.fields_for :address do |address_form| %>
twmills
  • 2,985
  • 22
  • 20
  • I just tried that and while I didn't get an error, the address fields aren't showing on the form. – Mike May 11 '11 at 19:35
  • You probably have to build an empty address object on Person first. – twmills May 11 '11 at 19:47
  • @user.person.address = Address.new – twmills May 11 '11 at 19:48
  • Excellent. I added <% resource.profile.address = Address.new%>. Thanks! – Mike May 11 '11 at 19:55
  • 1
    I should clarify, because this will cause you problems with updates. First I would add the address to person in the controller, since it's considered bad form to do that in the view. Secondly, you only want to add the new Address object only if the profile object doesn't have it already. Otherwise you will keep overwriting it. – twmills May 11 '11 at 19:59
  • I'm having to do it in the view since I don't see the devise controller to add it to. – Mike May 11 '11 at 20:01
  • OK, I am veering off into a tangent here, but you can create custom Devise controllers to manipulate if you like. Look under "Configuring controllers" in the devise README. Hope this helps! – twmills May 11 '11 at 20:09