🧑‍💻

【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ガイドに記載がありますので、
詳しく調べたい方はぜひこちらをご覧ください。
https://railsguides.jp/active_record_validations.html#カスタムバリデータ
以上となります。
最後までお読みいただき、ありがとうございました。

Discussion