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