Kyle Truscott
Kyle Truscott

Reputation: 1577

Validate presence of parent for has_many/new_record? situation

class Game < ActiveRecord::Base
  has_many :moves
end

class Move < ActiveRecord::Base
  belongs_to :game
  belongs_to :user

  validates_presence_of :user
  validates_presence_of :game # validator in question
end

#####

game = Game.new
move = current_user.moves.build
game.moves << move
game.save # => false
game.errors.mesages # => {:"moves.game"=>["can't be blank"]}

On game.save, ActiveRecord will automatically assign the newly created game to the move. validates_presence_of :game throws this off, though, since all the validations (for both game and move) are checked before save. Which totally makes sense.

Removing the game constraint on move obviously lets the records go through.... BUT I'd like to keep it around since most of the time moves are created in a more standalone fashion. For instance:

move      = current_user.moves.build
move.game = @game
move.save

So, my question: Should I just go ahead and remove that validator, and just ensure move.game is always set throughout the codebase? Or is there a magic way to keep it, and still utilize Game.new.moves << move

Upvotes: 1

Views: 248

Answers (1)

Kyle Truscott
Kyle Truscott

Reputation: 1577

With a bit more research, I figured out there IS a magic way. I just needed to add inverse_of options to both sides of the relationship. Not sure exactly how that helps ActiveRecord know how to pass the validator, but it works! Here are the updated models:

class Game < ActiveRecord::Base
  has_many :moves, inverse_of: :game
end

class Move < ActiveRecord::Base
  belongs_to :game, inverse_of: :moves
  belongs_to :user

  validates_presence_of :user
  validates_presence_of :game
end

#####

game = Game.new
move = current_user.moves.build
game.moves << move
game.save # => true

This answer had the :inverse_of solution: https://stackoverflow.com/a/4783112/2531850

Upvotes: 1

Related Questions