🔖
[Rails]カスタムバリデータを実装する
複数間のモデルで同じ条件で検証したい属性がある時、カスタムバリデータを作成することで
同じロジックを各モデルに実装する必要がなくなります。
カスタムバリデータには2種類ありますので、目的に合わせてどちらを使うか選択してください。
validatorクラスを自作する
まず、 validators
ディレクトリを作ってそこに hoge_validator.rb
を作成します。
Railsは、自動で hoge_validator
を読み取ってくれます。
個別の属性を検証する場合
1つの属性を検証したい時はEachValidatorが役に立ちます。
class DateValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.blank?
record.errors.add(attribute, '日付は今日より未来を選択してください') if value.to_date < Time.zone.today
end
end
EachValidatorを利用するには、ActiveModel::EachValidator
を継承したクラスを作成します。そしてこのバリデータクラスは必ず validate_each
メソッドを実装しなければいけません。validate_eachメソッドは次の3つの引数を受け取ります。
- record(モデルインスタンス)
- attribute(検証する属性)
- value(検証する属性値)
このカスタムバリデータは次の様にvalidatesメソッドを使って呼び出すことが出来ます。
class User < ApplicationRecord
validates :date, date: true
end
複雑な条件下で検証する必要がある場合
ActiveModel::Validator
を継承したクラスを実装します。このクラスは必ず validate
メソッドを実装する必要があります。validateメソッドは record(モデルのインスタンス)
を引数に受け取ります。
例として、Articleモデルには公開日(start_date)と公開終了日(end_date)があり、公開終了日は公開日以降でなければいけないことを検証するときは次の様になります。
class StartEndDateValidator < ActiveModel::Validator
def validate(record)
start_date = options[:start_date]
end_date = options[:end_date]
return unless start_date.present? && end_date.present? && start_date > end_date
record.errors.add(options[:end], :end_date_greater_than_start_date, start: record.class.human_attribute_name(options[:start]))
end
end
このカスタムバリデータを使うには次の様に validate_with
メソッドで呼び出します。
class ArticleForm
include ActiveModel::Model
include ActiveModel::Validations
include ActiveModel::Attributes
attribute :start_date, :date
attribute :end_date, :date
validate_with StartEndDateValidator, start: :start_date, end: :end_date, start_date: start_date, end_date: end_date
end
validate_with
の第二引数以降はoptionとしてバリデータクラスで使うことが出来ます。
Discussion