2013-10-23 56 views
7

我有一个使用条件定义的唯一约束。但是,下面的测试不及格:Mongoid:验证“validates_uniqueness_of”只会在特定字段发生变化时触发

class Dummy 
    include Mongoid::Document 

    field :name, :type => String 
    field :status, :type => Boolean 

    validates_uniqueness_of :name, if: :status 
end 


describe "UniquenessValidator" do 
    let!(:d1) { Dummy.create!(name: 'NAME_1', status: true) } 
    let!(:d2) { Dummy.create!(name: 'NAME_1', status: false) } 

    it "should raise an error" do 
    expect { 
     d2.status = true 
     d2.save! 
    }.to raise_error 
    end 
end 

由于name_changed?是假的,没有验证似乎发生,因此,唯一的条件没有被选中。

这是一个错误?或者我忘记了什么?我想这是一个优化,以避免每次修改元素时都运行验证。

在这种情况下,状态改变时触发验证的好方法是什么?

谢谢!

+3

[该mongoid文档(http://mongoid.org /en/mongoid/docs/validation.html)指出:“当在已经存在的数据上使用#valid?时,Mongoid与Active Record的行为略有不同.Active Record的#valid?将运行所有的验证,而Mongoid的#valid?将只运行验证内存中的文档作为优化。“也许这有帮助。 –

+0

@ p11y:确实(https://github.com/mongoid/mongoid/blob/3.1.0-stable/lib/mongoid/validations/uniqueness.rb#L289)。 hummm ... – Aymeric

+1

肮脏的解决方法:覆盖模型 def attribute_changed?(attr) 如果attr =='name'和self.status_changed? true else super end end – Aymeric

回答

5

当你的情况是一个边缘的情况下,我会建议你创建这个你自己的验证器类,这样的事情应该工作:

class NameUniquenessValidator < Mongoid::Validatable::UniquenessValidator 
private 
    def validation_required?(document, attribute) 
    return true "name" == attribute.to_s 
    super 
    end 
end 

class Dummy 
    include Mongoid::Document 

    field :name, :type => String 
    field :status, :type => Boolean 

    validates_with(NameUniquenessValidator, :name, if: :status) 
end 
+0

仅供参考,我已经创建了一个github问题:https://github.com/mongoid/mongoid/issues/3343 – Aymeric

+0

酷..我也会看看它。 –

1

您正在更新状态字段,因此您需要验证此字段。当您更新单场

class Dummy 
    include Mongoid::Document 

    field :name, :type => String 
    field :status, :type => Boolean 

    validates_uniqueness_of :name, if: :status 
    validates_uniqueness_of :status, scope: :name, if: :status 
end 

我不知道你是否可以强制mongoid验证所有字段:你可以做这样的事情。

+0

这似乎是向正确方向迈出的一步,但验证状态是唯一的,不幸的是在一般情况下不是可行的解决方案,即当依赖属性不唯一时。 –

+0

此外,您在'status'之前的最后一行中缺少一个冒号。编辑。 –

+0

是的,这是这种情况下的解决方案。对于一般情况,您需要根据状态属性为状态字段创建自定义验证。感谢您的更正。 – drinor

相关问题