[英]How do you add a custom uniqueness validation to an ActiveRecord model in Rails?
[英]How can I simulate a uniqueness validation error in an ActiveRecord model spec without the database?
我有一个ActiveRecord模型,它具有唯一性验证:
class Profile < ActiveRecord::Base
# fields: :name, :slug
before_validation :set_default_slug_from_name
validates :slug, uniqueness: {case_sensitive: false},
unless: -> { |p| p.slug.blank? }
# ...
end
现在,在编写此模型的规范时,我想模拟唯一性验证错误, 而不是访问数据库,因此我可以测试一些取决于这样的错误的模型行为:
describe Profile
before { subject.name = "Bob Greenfield" }
it "modifies the beginning of the slug if there is a duplicate" do
# simulate uniqueness conflict (duplicate record) here
subject.valid?
expect(subject.slug).to match(/^\w+-bob-greenfield$/)
end
end
我挖掘了实现UniquenessValidator
的Rails代码并尝试了以下方法:
allow_any_instance_of(ActiveRecord::Relation).to receive(:exists?).and_return(true)
# ...
但这似乎不起作用。
我想你在这里试图有点太深了。 虽然读取rails源并了解其工作原理非常棒,但是模拟Rails内部使用的每个类实例并不是一个好主意。 在这种情况下,与其他验证器相反,UniquenessValidator确实依赖于数据库,因此您应该:
一种。 允许自己点击数据库。 在这种情况下,这不是一个巨大的开销,也可能是最务实的方法。 你甚至在你的规范中的评论中使用“重复记录”,那么为什么不在那里有记录呢? 在10个案例中的9个案例中,这是正确的方法。 毕竟你正在检查一种ActiveRecord :: Base对象。
湾 检查独立于rails验证的行为。 无论如何应该这样做来测试你喜欢的slug格式。 最好在确认之前确保默认slug有效。 这里的缺点是,在这个调用和实际验证之前有一个很小的机会,slug将由其他人采取,但它与Rails内置的验证相同,所以我不担心它 - 你最终会有错误,下次尝试很可能会成功。
it "modifies the beginning of the slug on validation if there is a duplicate" do
Profile.stub(:slug_exists?).with("bob-greenfield").and_return(true)
Profile.stub(:slug_exists?).with("1-bob-greenfield").and_return(true)
Profile.stub(:slug_exists?).with("2-bob-greenfield").and_return(false)
subject.set_default_slug_from_name
subject.slug.should == "2-bob-greenfield"
end
并且您已经知道Rails在验证之前调用,因此您不必测试此行为。
此外,最好确保你对数据库有约束,Rails的唯一性是不够的: http : //robots.thoughtbot.com/the-perils-of-uniqueness-validations
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.