我在rails 3.1项目中使用了这种验证。
validates_presence_of :sales_price
validates_presence_of :retail_price
validates_numericality_of :sales_price, :greater_than => 0,
:allow_blank => true
validates_numericality_of :retail_price, :greater_than => 0,
:allow_blank => true
validate :sales_price_less_than_retail
def sales_price_less_than_retail
if sales_price >= retail_price
errors.add(:sales_price, "must be less than retail price.")
end
end
我正在使用rspec测试模型。当我只使用rails标准验证助手时,一切都很好。但是当我写自定义验证器(sales_price_less_than_retail)时,测试开始失败。
以下是测试代码:
it { should validate_presence_of :sales_price }
it { should validate_presence_of :retail_price }
it { should validate_numericality_of :sales_price }
it { should validate_numericality_of :retail_price }
这是工厂:
Factory.define :offer_option do |f|
f.sales_price rand(21) + 10 # $10-$30
f.retail_price { |a| a.sales_price * 2 }
end
当我运行测试时,我得到了这样的错误:
故障:
1)OfferOption
Failure/Error: it { should validate_presence_of :sales_price }
NoMethodError:
undefined method `>=' for nil:NilClass
# ./app/models/offer_option.rb:38:in `sales_price_less_than_retail'
# ./spec/models/offer_option_spec.rb:18:in `block (2 levels) in <top (required)>'
2)OfferOption
Failure/Error: it { should validate_presence_of :retail_price }
ArgumentError:
comparison of BigDecimal with nil failed
# ./app/models/offer_option.rb:38:in `>='
# ./app/models/offer_option.rb:38:in `sales_price_less_than_retail'
# ./spec/models/offer_option_spec.rb:19:in `block (2 levels) in <top (required)>'
我想一切都应该没问题,因为rspec应该单独测试验证器,但它似乎在我的测试中调用validates_presence_of之后调用自定义验证器。 当我删除自定义验证器时,问题就消失了。
我做错了什么?
答案 0 :(得分:6)
我认为这是因为validate_presence_of rspec helper set offer_option.sales_price = nil然后调用有效?在offer_option上。当调用有效?时,它会运行所有验证,因此您的自定义验证也是如此。然后你得到这个错误,因为nil上没有'&gt; ='方法。
如果您将sales_price_less_than_retail更改为:
def sales_price_less_than_retail
return if sales_prices.blank? || retail_price.blank?
if sales_price >= retail_price
errors.add(:sales_price, "must be less than retail price.")
end
end
然后它应该有用。