【Rails】validatorsでカスタムバリデータを共通化する
バリデーションは書くモデルの中で設定できますが、フォーマットのバリデーションなど毎回書くのは面倒です。
そこで何度も書くのは面倒なバリデーションを app/validatorsディレクトリ下で共通化する方法を解説します。
結論
# app/validators/email_format_validator.rb
class EmailFormatValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if /\A[a-zA-Z0-9_.\-]+@[A-Za-z0-9_.\-]+\z/.match?(value)
record.errors.add attribute, 'の形式が正しくありません'
end
end
class Hoge < ApplicationRecord
validates :email, email_format: true
end
解説
カスタムバリデータを作るには ActiveModel::EachValidator を継承する方法と、
ActiveModel::Validator を継承する方法の2つがあります。
ActiveModel::EachValidatorはカラム(属性)単位のカスタムバリデータを作成に使い、
ActiveModel::Validatorはオブジェクト全体に関するカスタムバリデータの作成に使います。
結論に書いたものはemail属性のフォーマットについてなのでActiveModel::EachValidatorを書きました。
作成にはまず、app/validatorsディレクトリを作成します。特にGemなどは必要ありません。
validatorsディレクトリ下にカスタムバリデータを書くファイルを作成してください。
ActiveModel::EachValidator
# app/validators/email_format_validator.rb
class EmailFormatValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if /\A[a-zA-Z0-9_.\-]+@[A-Za-z0-9_.\-]+\z/.match?(value)
record.errors.add attribute, 'の形式が正しくありません'
end
end
ActiveModel::EachValidatorの場合validate_eachメソッドを定義し、
引数にはrecord attribute valueの3つが必要です。
作成したカスタムバリデータを使用するには、ファイル名の_validatorより前を指定します。
class Hoge < ApplicationRecord
validates :email, email_format: true # <- email_format_validator.rbのemail_formatまでを指定
end
ActiveModel::Validator
# app/validators/name_combination_validator.rb
class NameCombinationValidator < ActiveModel::Validator
def validate(record)
if record.first_name.blank? && record.last_name.blank?
record.errors.add(:base, "姓か名のどちらかは入力してください")
end
end
end
ActiveModel::Validatorの場合はvalidateを定義します。
引数はrecordのみです。
このように複数の属性にわたる組み合わせなど、オブジェクト全体に関するカスタムバリデータの作成に使用します。
使用方法は以下のようにvalidates_withでクラス名を指定して使います。
class Fuga < ApplicationRecord
validates_with NameCombinationValidator
end
カスタムバリデータの詳しい使い方については、Railsガイドに記載がありますので、
詳しく調べたい方はぜひこちらをご覧ください。
以上となります。
最後までお読みいただき、ありがとうございました。
Discussion