Rails自定义验证从RSpec中的另一个验证调用

时间:2014-10-13 19:59:54

标签: ruby-on-rails ruby validation rspec

我的Rails应用程序有自定义验证。我在RSpec中使用validate_uniqueness_of,我的测试失败了。当我查看错误时,它会显示bad value for range

经过进一步检查,似乎只要调用validate_uniqueness_of,它也会调用我的自定义验证。它将参数作为nil进行测试。

如何防止这种碰撞发生?

模型

class Announcement < ActiveRecord::Base
  validates_presence_of :button, :link
  validates_uniqueness_of :start_date, :end_date
  validate :overlapping_start_dates, :overlapping_end_dates

  def date_range
    start_date..end_date
  end

  def overlapping_start_dates
    # binding.pry
    errors.add(:start_date, "cannot overlap with another announcement") unless self.class.where(start_date: start_date..end_date).empty?
  end

  def overlapping_end_dates 
    errors.add(:end_date, "cannot overlap with another announcement") unless self.class.where(end_date: start_date..end_date).empty?
  end 
end

RSpec的

describe Announcement do
  before { FactoryGirl.create(:announcement) }

  it { should validate_uniqueness_of :start_date }
  it { should validate_uniqueness_of :end_date }
  it { should validate_presence_of :button }
  it { should validate_presence_of :link }

  context 'when two announcements overlap' do
    it "should not save" do
      announcement = FactoryGirl.build(:announcement)
      expect(announcement.save).to eq(false) 
    end
  end

  after { Announcement.destroy_all }

end

1 个答案:

答案 0 :(得分:0)

所以我想我弄明白了。

来自validates_uniqueness_of file

  

买者

     

此匹配器的工作方式与其他匹配器略有不同。如前所述,如果已经存在,它将创建模型的实例。有时,此步骤会失败,尤其是如果您对除了唯一属性之外的任何属性具有数据库级限制。在这种情况下,解决方案是在调用validate_uniqueness_of之前使用值填充这些属性。

我正在为每次测试创建FactoryGirl对象而不是构建它。

工作代码

describe Announcement do
  # before(:all) { FactoryGirl.create(:announcement) }
  subject { FactoryGirl.build(:announcement) } 
  it { should validate_uniqueness_of :start_date }
  it { should validate_uniqueness_of :end_date }
  it { should validate_presence_of :button }
  it { should validate_presence_of :link }

  context 'when two announcements overlap' do
    it "should not save" do
      FactoryGirl.create(:announcement)
      announcement = FactoryGirl.build(:announcement)
      expect(announcement.save).to eq(false) 
    end
  end

  after { Announcement.destroy_all }

end