has_one and has_many associations: which side of the association is saved first

Posted by SeeBees on Stack Overflow See other posts from Stack Overflow or by SeeBees
Published on 2010-04-20T03:20:14Z Indexed on 2010/04/20 3:23 UTC
Read the original article Hit count: 323

Filed under:
|

I have three simplified models:

class Team < ActiveRecord::Base
  has_many :players
  has_one :coach
end

class Player < ActiveRecord::Base
  belongs_to :team
  validates_presence_of :team_id
end

class Coach < ActiveRecord::Base
  belongs_to :team
  validates_presence_of :team_id
end

I use the following code to test these models:

t = Team.new
team.coach = Coach.new
team.save!

team.save! returns true.

But in another test:

t = Team.new
team.players << Player.new
team.save!

team.save! gives the following error:

> ActiveRecord::RecordInvalid:
> Validation failed: Players is invalid
>   from
> /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:1090:in
> `save_without_dirty!'     from
> /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/dirty.rb:87:in `save_without_transactions!'  from
> /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in
> `save!'   from
> /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in
> `transaction'     from
> /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:182:in
> `transaction'     from
> /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in
> `save!'   from
> /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:208:in
> `rollback_active_record_state!'   from
> /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in
> `save!'   from (irb):14

I figured out when team.save! is called, it first calls player.save!. player needs to validate the presence of the id of the associated team. But at the time player.save! is called, team hasn't been saved yet, and therefore, team_id doesn't yet exist for player. This fails the player's validation, so the error occurs.

But on the other hand, team is saved before coach.save!, otherwise the first example will get the same error as the second.

So I've concluded that when a has_many bs, a.save! will save bs prior to a. When a has_one b, a.save! will save a prior to b. If I am right, why is this the case? It doesn't seem logical to me. Why has_one and has_many association have different order in saving? Any ideas? Thanks.

© Stack Overflow or respective owner

Related posts about ruby-on-rails

Related posts about activerecord