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 | 検証のタイミングを指定できる |
バリデーションに条件をつける
バリデーションif
やunless
オプションを利用し、条件を設定することができます。条件を設定することで指定条件時のみバリデーションを行うようになります。
シンボルを利用して条件をつける
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
を指定するとバリデーションがスキップされます。
実行すると上記のようにデータベースへ書き込みが行われてしまいました。