如何使用shoulda匹配器进行自定义验证?

时间:2015-07-12 21:46:06

标签: ruby-on-rails validation rspec

我无法解决如何让这些测试恢复绿色的问题。

模型

validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
    uniqueness: true
validates :zip, presence: true, format: { with: VALID_ZIP_REGEX }
validates_numericality_of :puzzle_pieces, only_integer: true

规格

it { should validate_presence_of(:email) }
it { should validate_uniqueness_of(:email) }
it { should allow_value('john.doe@example.com', 'alice@yahoo.ca').for(:email) }
it { should_not allow_value('john2example.com', 'john@examplecom').for(:email) }

it { should validate_presence_of(:zip) }
it { should allow_value('35124', '35124-1234').for(:zip) }
it { should_not allow_value('5124', '35124-12345').for(:zip) }

it { should validate_numericality_of(:puzzle_pieces).only_integer }

上述测试通过,直到我添加此自定义验证。

自定义验证器

class PiecesValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value > 0 && value <= Puzzle.remaining
      record.errors[attribute] << (options[:message] || "Puzzle pieces must be between 1 and #{Puzzle.remaining}")
    end
  end
end

模型

validates :puzzle_pieces, pieces: true

规格

it "does not allow a negative number of puzzle pieces to be saved" do
  order = build(:order, puzzle_pieces: -1)
  expect(order).to be_invalid
end

最后一次测试通过了,但是我的所有测试都失败并且出现了相同的错误

NoMethodError:
       undefined method `>' for nil:NilClass

我不明白如何解决这个问题。看来,shoulda测试在隔离状态下运行得很好。但是当添加自定义验证时,它们都会爆炸。

任何帮助我理解这一点的帮助都将非常感谢!

1 个答案:

答案 0 :(得分:3)

您的问题是您的验证不期望value为零。将您的方法更改为:

class PiecesValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value && value > 0 && value <= Puzzle.remaining
      record.errors[attribute] << (options[:message] || "Puzzle pieces must be between 1 and #{Puzzle.remaining}")
    end
  end
end

如果验证字段为空,则不会添加错误。但是,您可以使用标准rails验证器来实现您的目标:

validates :puzzle_pieces, numericality: { only_integer: true, less_then: Puzzle.remaining, greater_then: 0 }