views:

178

answers:

1

In rails, when saving an active_record object, its associated objects will be saved as well. But has_one and has_many association have different order in saving objects.

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 expected that when team.save is called, team should be saved before its associated coach and players.

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

I figured out that team.save! saves objects in the following order: 1) players, 2) team, and 3) coach. This is why I got the error: When a player is saved, team doesn't yet have a id, so validates_presence_of :team_id fails in player.

Can someone explain to me why objects are saved in this order? This seems not logical to me.

A: 

You should used "validates_associated" to accomplish that

check Here

Something like following no check though

class Team < ActiveRecord::Base
  has_many :players
  has_one :coach
  validates_associated :players, :coach  ###MOST IMPORTANT LINE 
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

In your controller

t = Team.new

@coach = t.build_coach(:column1=> "value1", :column2=> "value2" )  # This create new object with @coach.team_id= t.id
@players = t.players.build

t.save#This will be true it passes the validation for all i.e. Team, COach & Player also save all at once otherwise none of them will get saved.
Salil
This still raises ActiveRecord::RecordInvalid.
zetetic
please put your code with "validates_associated"
Salil
validates_associated only validates that the associated model is valid in itself, but doesn't validate that the associated model is present. For that, you need validates_presence_of.See http://github.com/rails/rails/blob/v3.0.0.beta.3/activerecord/lib/active_record/validations/associated.rb for the full details.
François Beausoleil
Can you associate a player with the team? Does that still pass the validation? Thanks.
Bryan
Isnt validates_associated set by default? (on a has_many)
Mike