Ruby
Rails
Validation

カスタムバリデートでバリデーション前編 初心者→中級者へのSTEP3/25

カスタムバリデートでバリデーション前編

はじめに
前回の記事ではControllerでのバリデーションの具体例としてフォームオブジェクトを紹介しました。今回はモデルでのバリデーションとして、ロジックな検証をカスタムバリデートを用いてしていきます。

カスタムバリデートとは

Railsに組み込まれているバリデーションだけでは足りない時、プロジェクト仕様のバリデーションルールを追加することになりますが、それを全てmodelに書くと可読性が悪くなります。管理も大変です。てな訳でバリデートクラスなるものを作って独自のルールをそこにまとめようということです。

個別のEachValidator

カスタムバリデータを追加するには二つのアプローチがあります。
まずは個別の属性にバリデートをかけるEachValidatorについて説明します。
今回はemailのバリデーションを例にします。emailがちゃんとemailの形式を取っているかのバリデーションです。

app/validtors/階層に、カスタムバリデータクラスとしてemail_validator.rbを作成します。

email_validator.rb
class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A[a-zA-Z0-9_\#!$%&`'*+\-{|}~^\/=?\.]+@[a-zA-Z0-9][a-zA-Z0-9\.-]+\z/
      record.errors[attribute] << (options[:message] || "はメールアドレスではありません")
    end
  end
end

個別の属性にバリデートをかけるカスタムバリデートを作成する場合、validate_eachを定義する必要があります。
validate_eachの引数、recordに呼び出し元のモデルインスタンスが入り、attributeに属性、valueに値が入ります。このメソッド内で呼び出し元のモデルインスタンスの属性値がemailとして正しい形式か検証しています。
ちなみに正規表現にて検証してますが、これにマッチしないとerrors[]にメッセージが格納されます。実はここの記述がないとエラー時にfalseを返してくれません。erros[]にエラーメッセージがあることで、そのデータは正しくないデータと判定します。

クラス名も重要です。~~Validatorとクラスを名付ければ,モデルにて:~~で呼び出せます。
つまり、下記のようになります。

User.rb
class User < ApplicationRecord
  validates :email, presence: true, email: true
end

これでemail属性にだけ先ほどカスタムバリデートクラスに記述した正規表現で検証できます。

まとめ

カスタムバリデートによる個別の属性の検証はこんな感じです。今回はルールがemailとして正しいかだけの検証だったのであまり差を感じませんが、もっと複雑なルールの場合、モデルにそれを書くよりこのカスタムバリデートクラスにまとめた方が、スッキリしていいですよね。
次回はもう一つのアプローチ、レコード一つ対象にバリデートをかけるものを説明してみます。

参考にしたの

Active Record バリデーション
https://railsguides.jp/active_record_validations.html#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%BF

【パーフェクトRails】バリデーションをクラスに分離する
https://waterlow2013.hatenablog.com/entry/2016/10/11/011312

メールアドレスの妥当性を正規表現でチェックする
http://rubytips86.hatenablog.com/entry/2014/03/28/135838