ActiveRecordは親から子供にエラーを付けるように出来てない

ActiveRecordは親から子供にエラーを付けるように出来てないという話.
 
こんな構造の事ね.

class Parent < ActiveRecord::Base
  has_many :children
end

class Child < ActiveRecord::Base
  belongs_to :parent
end

 
ActiveRecordでValidationする際,親から子供にエラーを付けたい場合があると思う.
例えば,子供のインスタンスのcodeが一意であるかとか.
しかし,Railsではvalid?を呼び出す際に自分のerrorsをクリアしてしまう.
 

# activerecord-2.1.2/lib/active_record/validations.rb
    def valid?
      errors.clear
# ...

 
Railsのお作法的には自分の事は自分自身でvalidationして欲しいみたいだ.
 
では親がもつ子供が一意のコードである事をvalidateするにはどうしたらいいだろうか.
validates_uniqueness_of使えばいいじゃんと思うがそれでは駄目だ.
 

class Child < ActiveRecord::Base
  validates_uniqueness_of :code, :scope => :parent_id
end

なぜなら,親が未登録の場合,子供のparent_idは空だからだ.
困った困った.どうしよう.
そういうときのIRCのfreenode#rails-tokyoチャンネル.
Railsユーザのエキスパートな人たちがいるわけだし,質問しない手はない.
 
そうすると,morohashiさんからスマートな答えを頂いた.

@parent.children.build(:parent => @parent)

とする方法.
子供を生成するときは必ず親のインスタンスを渡すようにすれば,新規登録時でも更新時でも問題ない.
ただ,このままでは使えなかったので以下の様なコードに直した.

class Parent < ActiveRecord::Base
  has_many :children

  def new_children(attrs)
    attrs.each{|a| a.update(:_paret => self)}
    self.children.build(attrs)
  end
end

class Child < ActiveRecord::Base
  belongs_to :parent

  @_parent
  attr_accessor :_parent

  validate :verify_uniqueness_code

  def verify_uniqueness_code
    parent = (@_parent || self.node)
    return unless parent
    hit = parent.node_attributes.inject(0) do |r, c|
      r +=1 if c.code == self.code
      r
    end
    if hit != 1
      self.errors.add(:code, ActiveRecord::Errors.default_error_messages[:taken])
      parent.errors.add(:node_attributes, ActiveRecord::Errors.default_error_messages[:invalid])
    end
  end
end

試してないけど動くと思う.
個人的には

    def valid?(errors_clearly=true)
      errors.clear if errors_clearly
# ...

ActiveRecordにあると嬉しいんだが...