3.3 バリデーション

バリデーションを定義する

  • 数値であることを検証するnumericality
class Post < ApplicationRecord
  validates :page_views, numericality: true, greater_than_or_equal_to: 0
end

numericalityは数値のみが利用されているかを検証します。デフォルトの設定では整数、浮動小数点にマッチします。 オプションを追加することでマッチする数値の種類を変更できます。

numericalityの利用可能なオプション

オプション
odd 奇数のみを許可
even 偶数のみを許可
equal_to 指定した値と同値のみ許可
greater_than 指定した値より大きい値のみ許可
greater_than_or_equal_to 指定した値以上の値のみ許可
less_than 指定した値より小さい値のみ許可
less_than_or_equal_to 指定した値以下の値のみ許可
only_integer 整数のみを許可
  • 値が存在ことを検証するpresence
class Post < ApplicationRecord
  validates :title, presence: true
end

presenceは値がnilや空文字でないかを検証します。

  • 値が存在しないことを検証するabsence
class Post < ApplicationRecord
  validates :title, absence: true
end

absenceは値がnilや空文字であるかを検証します。

  • 値が一意であることを検証するuniqueness
class User < ApplicationRecord
  validates :email, uniqueness: true
end

uniquenessは値が一意であり重複していないことを検証します。 注意しなければならないのは、このバリデーションはデータベースに一意性の制約をつける訳ではありません。

uniquenessの利用可能なオプション

オプション
scope 複合一意制限で利用する他の属性を指定する
case_sensitive 大文字、小文字を区別するか
  • 値の長さを検証するlength
class Post < ApplicationRecord
  validates :title, length: { minimum: 10 }
  validates :body, length: { maximum: 1000 }
end

lengthの利用可能なオプション

オプション
minimum 指定した長さ以上を許可
maximum 指定した長さ以下を許可
is 指定した同じ長さのみを許可
in/within 指定した範囲の長さのみ許可
  • 受け付ける値を検証するinclusion
class Post < ApplicationRecord
  validates :status, inclusion: { in: %w(draft published)
end

inclusionは値が指定したデータのまとまりに含まれているかを検証します。

  • 受け付ける値を検証するexclusion
class Site < ApplicationRecord
  validates :subdomain, exclusion: { in: %w(www us cn jp) }
end

exclusionは値が指定したデータのまとまりに含まれていないかを検証します。

  • 正規表現を利用して受け付ける値を検証するformat
class User < ApplicationRecord
  validates :username, format: { with: /\A[a-z0-9]+\z/i }
end

formatは値が指定した正規表現にマッチするかを検証します。

  • チェックを検証するacceptance
class User < ApplicationRecord
  validates :terms_of_service, acceptance: true
end

acceptanceはビューに設置したチェックボックスがチェックされているかを検証します。 サービス規約への同意の確認などに利用できます。

  • 値の確認の一致を検証するconfirmation
class User < ApplicationRecord
  validates :password, confirmation: true
end

confirmationは2つの値が完全一致する内容を受け取っているかを検証します。これを定義すると自動で_confirmationがついたフィールドが作成されます。

  • 共通で利用できるオプション
オプション
allow_nil nilの場合に検証をスキップ
allow_blank nilまたは空に場合に検証をスキップ
message 検証失敗時にerrorsに追加されるエラーメッセージを指定できる
on 検証のタイミングを指定できる

バリデーションに条件をつける

バリデーションifunlessオプションを利用し、条件を設定することができます。条件を設定することで指定条件時のみバリデーションを行うようになります。

シンボルを利用して条件をつける

class User < ApplicationRecord
  validates :terms_of_service, acceptance: true, if: :only_new_user

  private
    def only_new_user
      self.new_record?
    end
end

バリデーションの直前に実行したいメソッドを定義し、そのシンボルをifまたはunlessに渡すことができます。

Procを利用して条件をつける

class User < ApplicationRecord
  validates :terms_of_service, acceptance: true, if: Proc.new { |user| user.new_record? }
end

バリデーションの直前に実行したい処理をProcとして、ifまたはunlessに渡すことができます。

独自のバリデーションを定義する

独自のバリデーションメソッドを定義する

class Post < ApplicationRecord
  validates :published_at_after_created_at

  private
    def published_at_after_created_at
      unless self.published_at > self.created_at
        errors.add(:published_at, ": 公開日時は作成日時より後に設定してください")
      end
    end
end

バリデーションに利用したいメソッドを定義し、指定することで独自のバリデーションを定義することができます。エラーメッセージも指定することが可能です。

独自のバリデーターを定義する

class PublishedAtValidator < ActiveModel::Validator
  def validate(record)
    unless record.published_at > record.created_at
      errors.add(:published_at, ": 公開日時は作成日時より後に設定してください")
    end
  end
end

class Post
  include ActiveModel::Validations
  validates_with PublishedAtValidator
end

ActiveModel::Validatorを継承することで独自のバリデーターを定義して、バリデーションを行うことができます。 作成したクラスではvalidateメソッドが実装されている必要があります。 このメソッドはレコードが引数引数として取得でき、それに対しバリデーションを実行します。

バリデーションのエラーを取得する

class Post < ApplicationRecord
  validates :title, length: { minimum: 10 }
  validates :body, length: { maximum: 1000 }
end

上記のバリデーションをRailsコンソールで動作確認します。

$ post = Post.new
=> #<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil, published_at: nil>

$ post.valid?
=> false

$ post.errors
=> #<ActiveModel::Errors:0x00007fa44acd6630 @base=#<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil, published_at: nil>, @messages={:title=>["is too short (minimum is 10 characters)"]}, @details={:title=>[{:error=>:too_short, :count=>10}]}>

$ post.errors.messages
=> {:title=>["is too short (minimum is 10 characters)"]}

$ post.errors.full_messages
=> ["Title is too short (minimum is 10 characters)"]
メソッド
errors ActiveModel::Errorsのインスタンス
errors.messages モデルのカラムごとのエラーメッセージのハッシュ
post.errors.full_messages エラーメッセージの配列

バリデーションのエラー表示する

バリデーションで取得したエラーを表示するサンプルです。これ以外にも様々な方法で表示することが可能です。

<% if @post.errors.any? %> # エラーがあるかを確認
  <ul>
    <% @post.errors.full_messages.each do |msg| %> # エラーメッセージの配列をeachでそれぞれ出力する
      <li><%= msg %></li>
    <% end %>
  </ul>
<% end %>

バリデーションをスキップする

$ post = Post.new
=> #<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil, published_at: nil>

$ post.valid?
=> false

$ post.save(validate: false)
(0.9ms)  begin transaction
Post Create (4.1ms)  INSERT INTO "posts" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2018-06-25 05:23:58.696421"], ["updated_at", "2018-06-25 05:23:58.696421"]]
(2.8ms)  commit transaction
=> true

オブジェクトを保存するsaveメソッドのvalidate引数にfalseを指定するとバリデーションがスキップされます。 実行すると上記のようにデータベースへ書き込みが行われてしまいました。

results matching ""

    No results matching ""