2011-02-28 16 views
38

私は2つのモデルを持っています。
- Parenthas_manyChildren;
- Parentaccepts_nested_attributes_forChildren;ネストされたモデルと親のバリデーション

class Parent < ActiveRecord::Base 
    has_many :children, :dependent => :destroy 
    accepts_nested_attributes_for :children, :allow_destroy => true 
    validates :children, :presence => true 
end 

class Child < ActiveRecord::Base 
    belongs_to :parent 
end 

私は、すべての親に対して子どもの存在を検証するために検証を使用しているため、子なしの親を保存することはできません。

parent = Parent.new :name => "Jose" 
parent.save 
#=> false 
parent.children_attributes = [{:name => "Pedro"}, {:name => "Emmy"}] 
parent.save 
#=> true 

検証作業です。その後、我々は_destroy属性を経由して子供を破壊します:

parent.children_attributes = {"0" => {:id => 0, :_destroy => true}} 
parent.save 
#=> true !!! 
parent.reload.children 
#=> [] 

ので、私は、ネストされたフォームと検証を通じて、すべての子どもたちが通過します破壊することができます。私はそれをリロードする前に、私は_deleteを経由して私の親から子供を削除した後ので

実はそれが起こる、子供の方法は、まだ破壊されたオブジェクトを返すので、検証が渡さ:

parent.children_attributes = {"0" => {:id => 0, :_destroy => true}} 
parent.save 
#=> true !!! 
parent.children 
#=> #<Child id:1 ...> # It's actually deleted 
parent.reload.children 
#=> [] 

が、それはバグですか?

質問は何ですか。問題はそれを修復する最良の解決策です。私のアプローチは、Childにbefore_destroyフィルターを追加して最後のものかどうかを確認することです。しかし、それはシステムを複雑にします。

答えて

57

これはおそらくあなたのために働くでしょうが、私はそこにはるかに良い答えがあると感じています。私にはバグのように聞こえる。

class Parent 
    validate :must_have_children 

    def must_have_children 
    if children.empty? or children.all? {|child| child.marked_for_destruction? } 
     errors.add(:base, 'Must have at least one child') 
    end 
    end 
end 
+0

それでも 'Child'側で妥当性を確認する方が良いです:)感謝 – fl00r

+2

と' marked_for_destruction? 'のおかげで – fl00r

+0

この検証方法はまだRails 3.0.6で必要です – astjohn

0

これはバグではありません。マニュアルを

をAcordingすると、指定 属性が空白でないことを検証します( は、オブジェクト#空白によって定義されている?)

validates :children, :presence => trueはちょうど同じです。ドキュメンテーションは、あなたが関連でそれを使用しようとすると何が起こるかは述べていません。 validateを使用してカスタム検証を行う必要があります。

validates_presence_ofhas_manyに使用すると、関連付けのblank?アソシエートchildren(Arrayクラスのオブジェクト)が呼び出されます。 blank?Arrayに対して定義されていないため、method_missingが発生し、これはRails内で捕捉されます。通常、それはあなたが望むことをしますが、Rails 3.1rcとRuby 1.8.7では本当にひどい方法で失敗しています。関連するレコードの変更を静かに元に戻します。何が起こっているかを知るには数時間かかりました。

+2

実際に問題は、子どもたちを取り除く前に子供たちの存在を和らげるためです。だから、子供たちが 'marked_for_destruction? 'であるかどうかを調べるべきです。 – fl00r

関連する問題