2011-02-28 67 views
38

我有兩個模型。
- Parenthas_manyChildren;
- Parentaccepted_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 
#=> [] 

它是錯誤嗎?

是什麼問題。問題是修復它的最佳解決方案。我的方法是將before_destroy過濾器添加到Child以檢查它是否是最後一個。但它使系統變得複雜。

回答

57

這可能適合你,但我有一種感覺,那裏有更好的答案。這聽起來像是一個bug。

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 2011-02-28 16:45:46

+2

和感謝'marked_for_destruction?' – fl00r 2011-02-28 16:51:06

+0

這種驗證方法仍然需要像Rails 3.0.6的 – astjohn 2011-04-21 13:35:42

0

這不是一個錯誤。 Acording的文檔

驗證指定的 屬性不爲空(如對象#空白定義 ?)

validates :children, :presence => true僅僅是相同的。該文檔沒有說明如果您嘗試在關聯上使用它會發生什麼情況。您應該使用自定義驗證使用validate

使用validates_presence_ofhas_many協會呼籲blank?上關聯children,這是類Array的對象。由於blank?沒有爲Array定義,因此它觸發了在Rails中捕獲的method_missing。通常它會按照你的意願做,但是我發現它在Rails 3.1rc和Ruby 1.8.7中以一種非常糟糕的方式失敗了:它默默地恢復了相關記錄的變化。我花了幾個小時才知道發生了什麼事。

+2

其實這個問題,因爲它在兒童開除之前無視兒童的存在。所以我們應該檢查孩子是否被「標記爲破壞」? – fl00r 2011-05-31 11:06:56