This project is archived and is in readonly mode.

#2777 ✓resolved
flip

Updating nested attributes with has_one relationship doesn't work correctly

Reported by flip | June 7th, 2009 @ 08:59 PM | in 2.x

Updating the attributes of the child model results in the creation of a new Object with nil values when using a has_one relationship and nested attributes.

>> u = User.find 1
=> #<User id: 1, login: "james", password: "secret", created_at: "2009-06-06 22:50:07", updated_at: "2009-06-06 22:50:07">
>> u.profile
=> #<Profile id: 2, user_id: 1, age: 18, city: "London", comment: "", created_at: "2009-06-06 22:51:45", updated_at: "2009-06-06 22:51:45">
>> u.attributes = {:profile_attributes => {:city => 'nowhere'}}
=> {:profile_attributes=>{:city=>"nowhere"}}
>> u.profile
=> #<Profile id: nil, user_id: 1, age: nil, city: "nowhere", comment: nil, created_at: nil, updated_at: nil>
>> u.profile.changes
=> {"city"=>[nil, "nowhere"], "user_id"=>[nil, 1]}

I've described the full scenario at
http://railsforum.com/viewtopic.php?id=31491

Comments and changes to this ticket

  • Eloy Duran

    Eloy Duran June 7th, 2009 @ 09:23 PM

    • State changed from “new” to “invalid”

    You should include the id of the Profile to indicate it's an update you're trying to perform.

    u.attributes = {:id => 2, :profile_attributes => {:city => 'nowhere'}}
    

    For more info take a look at what the form helpers produce.

  • flip

    flip June 7th, 2009 @ 09:34 PM

    ok, i guess you mean:

    u.attributes = {:profile_attributes => {:id => 2, :city => 'nowhere'}}
    

    is this documented somewhere? Using the "old way" my approach would work also without the id:

    u.profile.attributes = {:city => 'nowhere'}
    
  • Eloy Duran

    Eloy Duran June 7th, 2009 @ 09:46 PM

    Oops, yeah that's what I meant :)

    It's shown here: http://github.com/rails/rails/blob/master/activerecord/lib/active_r...

    It is needed to differentiate between a new record or an existing one.

  • Greg

    Greg June 26th, 2009 @ 12:00 AM

    I'm not so sure that this should be invalid. It makes sense to need the id for has_many relationships, but for belongs_to and has_one, you should assume that they want to update the record.

    In the example that flip gave, calling u.save will return no problem, and you'll end up with an orphaned profile in the database. This scenario can easily come up if you are allowing updates via REST/XML...a user can PUT


    nowhere

    to http://&lt;>/users/2 or wherever. The user doesn't know the ID of the nested model, but they should expect that only the city is updated in the profile, a new profile should not be created.

    Unfortunately, I don't have a patch for this right now, but I believe this should be re-opened as a bug. Thanks!

  • Sébastien Luquet

    Sébastien Luquet October 5th, 2009 @ 02:00 PM

    Hi,

    Documentation is about update_attributes

    params = { :member' => { :avatar_attributes => { :id => '2', :icon => 'sad' } } }
    member.update_attributes params['member']

    What about object creation

    params = { :member' => { :avatar_attributes => { :id => '2', :icon => 'sad' } } }
    Member.create params['member']

    Does it create new Member, update Avatar with id 2 and associate the two record together ?

  • Dmitry Polushkin

    Dmitry Polushkin October 21st, 2009 @ 01:19 PM

    I agree that it should be reopened. Not smart to pass id for one to one.

  • Eloy Duran

    Eloy Duran October 21st, 2009 @ 01:39 PM

    I'd rather see a patch that adds something like :only_update => true' to accepts_nested_attributes_for. Or otherwise fix it in your controller if you don't trust the client.

  • Dmitry Polushkin

    Dmitry Polushkin November 1st, 2009 @ 02:33 PM

    Question, how to solve:

    class Team
      has_one :captain, :class_name => 'Player'
      accepts_nested_attributes_for :captain
    end
    
    class Player
      belongs_to :team
    
      validate :validate_team
    
      private
    
      def validate_team
        raise 'Should have team' unless team
      end
    end
    
    Team.create!(:captain_attributes => {:name => 'Name Surname'})
    

    Will be risen 'Should have team' because while attributes assigns to the nested model object, belongs_to associations isn't assigns.

    If you know how to solve that, please tell me.

    Thank you.

  • Eloy Duran

    Eloy Duran December 28th, 2009 @ 11:17 PM

    • State changed from “invalid” to “resolved”

    Today a patch for :update_only and the ability to use :inverse_of, which fixes the last issue, have both been pushed. HTH

  • Ryan Bigg

    Ryan Bigg October 9th, 2010 @ 10:00 PM

    • Tag cleared.
    • Importance changed from “” to “Low”

    Automatic cleanup of spam.

  • Jeff Kreeftmeijer
  • bingbing

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Referenced by

Pages