has_oneとhas_manyの違いは多重度だけという思い込み


のせいで、
親モデルと同時に子モデルをsaveする時
子モデルがinvalidだったら、親モデルも保存しない。

これがhas_oneでは素直にできませんでした。

class Parent < ActiveRecord::Base
  has_one :first_child

  validates :name, presence: true
end

class FirstChild < ActiveRecord::Base
  validates :name, presence: true
end
parent = Parent.new(name: 'Oya')
parent.first_child = FirstChild.new
parent.save
# => true

parent.valid? # => true
parent.persisted? # => true

parent.first_child.valid? # => false
parent.first_child.persisted? # => false

has_manyと同じ挙動を期待していますが、
FirstChildinvalidなのに、Parentが保存されてしまいます。

Parentが保存されないようにするには、このようにします。

class Parent < ActiveRecord::Base
  has_one :first_child, validate: true

  validates :name, presence: true
end

class FirstChild < ActiveRecord::Base
  validates :name, presence: true
end
parent = Parent.new(name: 'Oya')
parent.first_child = FirstChild.new
parent.save
# => false

parent.valid? # => false
parent.persisted? # => false

parent.first_child.valid? # => false
parent.first_child.persisted? # => false

has_oneを宣言する時に、validateオプションをtrueにすると
期待通りになります。

ちなみにhas_manyは、このオプションはデフォルトでtrueです。

参考