書いてあること
- 簡単な Validator の作り方
- RSpec のテストの書き方
Validator を作る
app/validators に Validator を追加していきます。
今回は Rails 標準の validates_numericality_of の単純に大小比較するだけのやつを作ります。
↓使用イメージとしてはこんな感じで
class Hoge
validates :value1, greater_than: :value2
end
↓ Validator のコードはこんな感じ
app/validators/greater_than_validator.rb
class GreaterThanValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value > record[options[:with]]
record.errors[attribute] << (options[:message] || "must be greater than #{options[:with]}")
end
end
-
record
には検証対象のレコード -
attribute
には検証対象の要素名の Symbol -
value
には検証対象の要素に入っている値
が入ってきます。
それとは別に Validator に指定した要素が諸々 options
の中に入ってます。今回の場合は :value2
という Symbol です。他に色々指定した場合は色々入ってくると思うので、そこは色々試してみてください。
テストを書く
spec/validators/greater_than_validator_spec.rb
require 'rails_helper'
describe GreaterThanValidator, type: :validator do
let(:clazz) do
Struct.new(:value1, :value2) do
include ActiveModel::Validations
validates :value2, greater_than: :value1
end
end
describe '#validate_each' do
subject { clazz.new(value1, value2) }
context 'when value1 higher than value2' do
let(:value1) { 1 }
let(:value2) { value1 + 99 }
it { is_expected.to be_valid }
end
context 'when value1 lower than value2' do
let(:value1) { 1 }
let(:value2) { value1 - 99 }
it { is_expected.not_to be_valid }
end
context 'when value1 equal value2' do
let(:value1) { 1 }
let(:value2) { value1 }
it { is_expected.not_to be_valid }
end
end
describe 'error messages' do
subject { object.errors.messages }
let(:object) { clazz.new(100, 0) }
before { object.validate }
it { is_expected.to eq(value2: ['must be greater than value1']) }
end
end
ポイントとしては let(:clazz)
の部分で、 Struct.new
を使って include ActiveModel::Validations
することで検証対象のモデルをテスト用に作れるという感じです。
あとは素朴に be_valid
とかやってるだけ。