0

在嵌套表單中,我希望用戶能夠同時創建或修改所有ParentChilds。因此,讓我們使傳遞的PARAMS是這樣的:Rails如何驗證跨嵌套子對象的唯一性

{"childs_attributes" => [{attribute:1}, {attribute:2}, {attribute:3}...]} 

我想驗證,對於任何一個Parent稱,attribute一切都其Childs必須是唯一的。換句話說,在上面的例子中,這是可以的,因爲你會得到:

Parent.childs.pluck(:attribute).uniq.length == Parent.childs.pluck(:attribute).length 

但是,如果PARAMS傳遞就像下面,這將會是驗證規則的違反:

{"childs_attributes" => [{attribute:1}, {attribute:2}, {attribute:3}...]} 

到目前爲止,我已經想出來做這個驗證的唯一解決方案是在Controller中......我知道這是不好的做法,因爲我們想把它推到模型上。

的問題是,如果在模型中我有類似下面:

class Parent 
    validate :unique_attribute_on_child 

    def unique_attribute_on_child 
    attribute_list = self.childs.pluck(:attribute) 
    if attribute_list.uniq.length != attribute_list.length 
     errors[:base] << "Parent contains Child(s) with same Attribute" 
    end 
    end 
end 

這是行不通的,因爲self.childs.pluck(:attribute)不會返回在當前的更新通過attribute,因爲當前的更新拿下還沒有儲蓄。

我想我可以做一些類似於after_save的東西,但是這感覺真的很複雜,因爲它回溯並顛倒了數據庫提交(更不用說,下面寫的代碼[未經測試,只是一個例子]可能導致循環循環如果我不小心,因爲父驗證關聯的孩子)

after_save :unique_attribute_on_child 

def unique_attribute_on_child 
    attribute_list = self.childs.pluck(:attribute) 
    if attribute_list.uniq.length != attribute_list.length 
     self.childs.each { |c| c.update_attributes(attribute:nil) } 
     errors[:base] << "Parent contains Child(s) with same Attribute" 
    end 
    end 
end 

其他想法?

回答

0

我的第一個衝動是建議Rails使用智能多元化,並嘗試使用children而不是childs,但我認爲這僅僅是一個例子。

我現在建議你改變你的策略。打電話給兒童驗證如下:

class Child < ActiveRecord::Base 
    belongs_to :parent 
    ... 
    validates :child_attribute, uniqueness: { scope: :parent } 
    ... 
end