【Rails】完全解説!Railsのバリデーションの使い方をマスターしよう!

Rails

バリデーションとは

データベースに保存する前に保存する内容を検証する機能です。

バリデーションとは?
リンクをコピーしました

投稿フォームで何かを投稿するとき、「入力必須項目」というのを目にしたことはないでしょうか?
例えば名前やメールアドレス、パスワードなどです。

このとき、入力必須項目に何も入力しないで投稿をすると投稿ができないようにしたいですね。

バリデーション

他にもパスワードなどは4文字以上であるとか、すでにデータベースに存在しているメールアドレスで登録できないようにするとかデータを保存する前に検証したいときもあります。

そんなときに定義するのがバリデーションです。
バリデーションを定義するとデータベースに保存する際、投稿された内容を検証し、保存するかどうかをチェックできるようになります。

バリデーションを定義すると下記のメソッドが動く前に必ず検証が行われます。

  • save
  • save!
  • create
  • create!
  • update
  • update!

saveとupdateは検証でデータが保存されない場合はfalseを返します。

ターミナル
1
2
3
4
5
6
[1] pry(<UsersController>)> @user.save
   (0.2ms)  BEGIN
  ↳ (pry):1
   (0.2ms)  ROLLBACK
  ↳ (pry):1
=> false
ターミナル
1
2
3
4
5
6
[1] pry(<UsersController>)> @user.update(user_params)
   (0.2ms)  BEGIN
  ↳ (pry):1
   (0.2ms)  ROLLBACK
  ↳ (pry):1
=> false

createは保存されてもされなくてもオブジェクト自身を返します。

ターミナル
1
2
3
4
5
6
7
8
9
10
[1] pry(<UsersController>)> User.create(name: "")
   (0.2ms)  BEGIN
  ↳ (pry):1
   (0.4ms)  ROLLBACK
  ↳ (pry):1
=> <User:0x007fd8bf0d0d28
 id: nil,
 name: "",
 created_at: nil,
 updated_at: nil>

バリデーションを定義してみよう
リンクをコピーしました

それではバリデーションを定義してみましょう。
バリデーションはモデルでも定義できますし、マイグレーションファイル に定義することもできます。

モデルに記入
リンクをコピーしました

モデルでバリデーションを定義するには下記のように記述します。

モデル
1
validates :カラム名, ヘルパー

ヘルパーを使うとどういう検証を行うのかを定義することができます。
ヘルパーの部分は後述します。

下記のように同時に複数のカラムを指定することもできます。

モデル
1
validates :カラム名, :カラム名, :カラム名, ヘルパー

マイグレーションファイル に記入
リンクをコピーしました

入力必須という検証をモデルに定義しただけだとRails側で保存させないだけなので、投稿フォーム経由での保存はできなくさせますが、SQLから実行するとデータは保存できてしまいます。
ですのでSQL側でも検証をさせておくと安心です。

その場合はマイグレーションファイル にバリデーションの定義をします。
マイグレーションファイル には下記のように記述します。

マイグレーションファイル
1
t.カラムの型 :カラム名, null: false

このように「null: false」と指定すると入力必須になります。
「t.timestamps」だけはデフォルトで「null: false」になっています。
入力必須でない場合は「null: true」にすればOKです。

例えばnicknameカラムに「null: false」としておくとnicknameカラムが空の時にはsqlの方で検証をしてROLLBACKさせ、保存されなくさせます。

ターミナル
1
2
3
4
5
6
7
8
9
10
  Parameters: {"utf8"=>"✓", "user"=>{"nickname"=>"", "commit"=>"送信"}
   (2.6ms)  BEGIN
  ↳ app/controllers/users_controller.rb:11
  User Create (1.6ms)  INSERT INTO `users` (`nickname`, `created_at`, `updated_at`) VALUES ('', 1, '2019-08-18 07:27:54', '2019-08-18 07:27:54')
  ↳ app/controllers/users_controller.rb:11
   (0.2ms)  ROLLBACK
  ↳ app/controllers/users_controller.rb:11
Completed 500 Internal Server Error in 13ms (ActiveRecord: 4.4ms)

ActiveRecord::NotNullViolation (Mysql2::Error: Field 'nickname' doesn't have a default value: INSERT INTO `users` (`nickname`, `created_at`, `updated_at`) ):

バリデーションのヘルパー
リンクをコピーしました

railsにはバリデーションのヘルパーが多数用意されています。
このヘルパーを使うとどういう検証を行うかを定義することができます。
主なヘルパーを紹介します。

presence
リンクをコピーしました

一番多く使うヘルパーです。
定義すると「空でないか」を検証します。

モデル
1
validates :カラム名, presence: true

下記のように記述するとnameカラムにちゃんと値が入っているかを検証します。

モデル
1
validates :name, presence: true

なのでこのカラムに何も入っていないときは保存されません。

absence
リンクをコピーしました

presenceとは逆で定義すると「空であるか」を検証します。

モデル
1
validates :カラム名, absence: true

uniqueness
リンクをコピーしました

値が一意(unique)であり重複していないかを検証します。
メールアドレスなど重複しては困るときに使います。

モデル
1
validates :カラム名, uniqueness: true

このように定義するとカラムにすでに存在している内容と同じものがあるかどうかを検証することができます。
すでに値が存在しているものと同じ値であれば保存されません。

acceptance
リンクをコピーしました

チェックボックスがオンになっているかどうかを検証します。
サービスに対する利用条項を読んで、「同意した」などのチェックボックスがあるサイトをよく見かけるかと思います。
そのときチェックボックスにチェックが入っているかを検証するときなどに利用します。

モデル
1
validates :カラム名, acceptance: true

confirmation
リンクをコピーしました

2つのフォームで入力された内容が完全に一致するかを検証します。
メールアドレスのフォームとメールアドレスの確認フォームのが全く同じであるか検証したいときなどに利用します。

モデル
1
validates :カラム名, confirmation: true

確認したいフォームのカラム名は末尾に「_confirmation」をつけます。
メールアドレスを例にすると下記のようになります。

モデル
1
2
validates :email, confirmation: true
validates :email_confirmation, presence: true

inclusion
リンクをコピーしました

値が指定した文字になっているかを検証します。
基本的にinオプションと一緒に使用します。

モデル
1
2
3
4
5
# 1つのワードの指定
validates :カラム名, inclusion: { in: ["検証したい文字"] }

# 複数のワードの指定
validates :カラム名, inclusion: { in: ["検証したい文字1", "検証したい文字2"] }

上の複数のワードの指定時のコードは下記のように%記法を使って書くこともできます。

モデル
1
validates :カラム名, inclusion: { in: %w(検証したい文字1 検証したい文字2) }

例えば文字の大きさを入力するフォームがあったとき、必ず「大」、「中」、「小」のいずれかの文字にしてもらいたい場合があるとします。
その時は下記のように指定すればこの3文字以外の文字が入力された時には保存がされないようにすることができます。

モデル
1
validates :size, inclusion: { in: %w(大 中 小) }

この時はたとえ「特大」のように文字の中に「大」が入っていたとしても「大」か「中」か「小」という文字でなければ保存されません。
このように特定の文字だけを保存したい時に使用します。

exclusion
リンクをコピーしました

指定された値が含まれていないかを検証します。
基本的にinオプションと一緒に使用します。

モデル
1
validates :カラム名, exclusion: { in: ["検証したい文字1", "検証したい文字2"] }

上のコードは下記のように%記法を使って書くこともできます。

モデル
1
validates :カラム名, exclusion: { in: %w(検証したい文字1 検証したい文字2) }

保存したくない文字を指定する時に使います。
例えばユーザー名に「管理人」とつけて欲しくない場合は下記のように指定します。

モデル
1
validates :name, exclusion: { in: %w(管理人) }

このようにすると「管理人」と入力された場合は保存されないようにすることができます。
「管理人A 」の場合は保存されます。

length
リンクをコピーしました

値の長さを検証します。
下記のオプションを使って定義します。

オプション名 内容
minimum 最小値を指定します
maximum 最大値を指定します
in 長さの範囲を指定します
is 値の長さを指定します

具体的には下記のように使用します。

モデル
1
2
3
4
validates :カラム名, length: { minimum: 2 } #最低でも2文字以上であるか
validates :カラム名, length: { maximum: 6 } #6文字以内であるか
validates :カラム名, length: { in: 5..10 } #5文字から10文字以内であるか
validates :カラム名, length: { is: 5 } #5文字であるか

format
リンクをコピーしました

正規表現と属性の値が合致するかの検証をします。
withオプションと併用して使います。

モデル
1
validates :カラム名, format: { with: 正規表現 }

下記のように正規表現で指定します。

モデル
1
validates :name, format: { with: /\A[a-zA-Z]+\z/ }

上のコードは半角英文字だけ入力を許可することを意味します。
なので「pikawaka」は保存され、「ピカわか」だと保存されません。

numericality
リンクをコピーしました

属性に数値のみが使われているかを検証します。

モデル
1
validates :カラム名, numericality: true

バリデーションのオプション
リンクをコピーしました

オプションには全てのヘルパーで使うことができるものがあります。

on
リンクをコピーしました

検証が行われるタイミングを指定することができます。

モデル
1
validates :カラム名, ヘルパー, on: :メソッド名

下のように記述するとcreateメソッドが実行されたときにだけ一意かどうかの検証が行われます。

モデル
1
validates :email, uniqueness: true, on: :create

saveメソッドはcontextパラメータで「on: :hoge」のhogeの部分を指定することができます。

railsファイル
1
2
3
4
5
6
# モデル
validates :email, uniqueness: true, on: :create_account

# コントローラー
@user.save(context: :create_account)
# 独自に作成したcreate_acountというメソッドが実行された時にだけ検証が行われる

例えばユーザー登録の時はemailと名前だけ保存されれば良いけれど、その後、商品を購入したい時にはユーザー編集ページでユーザー情報に住所を入力する必要があるとします。
その際には下記のようにすれば更新する時にだけ住所が入力されているかを検証させることができます。

モデル
1
2
3
4
5
6
# emailとnameは作成時と更新時どちらも検証が行われる
validates :email, presence: true
validates :name, presence: true

# addressは更新時のみ検証が行われる
validates :address, presence: true, on: :update

message
リンクをコピーしました

バリデーションが失敗した時に全てのエラーメッセージが入っているerrorsコレクションという場所に自分で作成したカスタムエラーメッセージを追加することができるオプションです。
指定をしていない場合はデフォルトで用意されているメッセージが表示されます。

モデル
1
validates :カラム名, ヘルパー: { message: "出力されるメッセージ" }

下記のように記述するとnameカラムがnilだった場合のエラーメッセージが「名前を入力してください」となります。

モデル
1
validates :name, presence: { message: "名前を入力してください" }

エラーメッセージとは何かについては後述するerrorsメソッドを参照してください。

allow_nil
リンクをコピーしました

値がnilの場合、検証を行わなくすることができます。

モデル
1
validates :カラム名, ヘルパー,  allow_nil: true

何も入力しないときは検証したくない場合は下記のように記述します。

モデル
1
validates :name, length: { minimum: 2 },  allow_nil: true

allow_blank
リンクをコピーしました

nilや空文字など値がblank?に該当する場合、検証を行わなくすることができます。
上の「allow_nil」と似ていますが、「allow_nil」は空文字を入力した場合(フォームに何も入力しなかった場合)は検証をしてしまいますが、「allow_blank」だと検証をスキップさせることができます。

モデル
1
2
3
4
5
6
7
# この場合空文字を入力するとバリデーションの検証が実行される
# つまり1文字以下の場合は検証が行われROLLBACKされる
validates :name, length: { minimum: 2 },  allow_nil: true

# この場合空文字を入力するとバリデーションの検証はスキップされる
# つまり1文字以下の場合の検証がスキップされるので保存される
validates :name, length: { minimum: 2 },  allow_blank: true

便利なメソッド
リンクをコピーしました

その他の便利なメソッドを紹介します。

valid?
リンクをコピーしました

検証をするメソッドです。
検証は上で紹介したメソッドが実行される前に行われますが、このメソッドを使用しても検証が実行されます。

例えばnewメソッドは実行時には検証が行われないので、newされた時に保存されるかを確認したい時に使用します。
もし保存できる状態であればtrueが、検証で引っかかって保存できない状態であればfalseが返ります。

モデル
1
validates :text, presence: true
ターミナル
1
2
3
4
5
6
7
8
9
[1] pry(main)> article = Article.new(text: "")
=> #<Article:0x007fc5b3b6d6d8
 id: nil,
 text: "",
 created_at: nil,
 updated_at: nil,
 user_id: nil>
[2] pry(main)> article.valid?
=> false

詳しい使い方については後述します。

invalid?
リンクをコピーしました

valid?メソッドの逆の返り値を返すメソッドです。
保存できる状態であればfalseが、検証で引っかかって保存できない状態であればtrueが返ります。

errors
リンクをコピーしました

valid?メソッドを使った後にerrorsメソッドを使うと今起きているエラーをエラーメッセージとして確認することができます。

モデル
1
validates :text, presence: true
ターミナル
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[1] pry(main)> article = Article.new(text: "")
=> #<Article:0x007fc5b3b6d6d8
 id: nil,
 text: "",
 created_at: nil,
 updated_at: nil,
 user_id: nil>
[2] pry(main)> article.valid?
=> false
[3] pry(main)> article.errors
=> #<ActiveModel::Errors:0x007fc5b85158f8
 @base=
  #<Article:0x007fc5b3b6d6d8
   id: nil,
   text: "",
   created_at: nil,
   updated_at: nil,
   user_id: nil>,
 @messages={:text=>["can't be blank"]}>

最後の行がエラーメッセージです。
ここでは「can't be blank」、つまり「空白にはできません」という原因で保存されていないのがわかります。
このようにどのような検証が行われて保存できないかをエラーコードで確認することができます。

errors[:カラム名]
リンクをコピーしました

カラムを指定してエラーメッセージを確認することができます。

モデル
1
validates :text, presence: true
ターミナル
1
2
3
4
5
6
7
8
9
10
11
[1] pry(main)> article = Article.new(text: "")
=> #<Article:0x007fc5b3b6d6d8
 id: nil,
 text: "",
 created_at: nil,
 updated_at: nil,
 user_id: nil>
[2] pry(main)> article.valid?
=> false
[3] pry(main)> article.errors[:text]
=> ["can't be blank"]

errors.messages
リンクをコピーしました

カラムごとのエラーメッセージを一度に確認することができます。

モデル
1
validates :text, presence: true
ターミナル
1
2
3
4
5
6
7
8
9
10
11
12
[1] pry(main)> article = Article.new(title: "hoge", text: "")
=> #<Article:0x007fc5b3b6d6d8
 id: nil, 
 title: "hoge",
 text: "",
 created_at: nil,
 updated_at: nil,
 user_id: nil>
[2] pry(main)> article.valid?
=> false
[3] pry(main)> article.errors.messages
=> {:text=>["can't be blank"]}

errors.full_messages
リンクをコピーしました

詳細なエラーメッセージを確認することができます。

モデル
1
validates :text, presence: true
ターミナル
1
2
3
4
5
6
7
8
9
10
11
[1] pry(main)> article = Article.new(text: "")
=> #<Article:0x007fc5b3b6d6d8
 id: nil,
 text: "",
 created_at: nil,
 updated_at: nil,
 user_id: nil>
[2] pry(main)> article.valid?
=> false
[3] pry(main)> article.errors.full_messages
=> ["Text can't be blank"]

バリデーションに条件をつけよう
リンクをコピーしました

オプションを使うと条件付きで検証を行うことができます。

:if
リンクをコピーしました

特定の条件の時に検証を行う必要がある時に使用するオプションです。

モデル
1
validates :カラム名, ヘルパー, if: :条件式やメソッド

deviseで定義されているuser_signed_in?というヘルパーメソッドを使ってユーザーがログインしている時だけ検証をすることができたりします。

モデル
1
validates :text, presence: true, if: :user_signed_in?

:unless
リンクをコピーしました

ifオプションと同じで特定の条件の時に検証を行う必要がある時に使用するオプションです。
ifとは逆で条件式がfalseの時にだけ検証をすることができます。

with_options
リンクをコピーしました

1つの条件を複数のバリデーションで使いたい時に使用します。

モデル
1
2
3
4
with_options if: :条件式やメソッド do |変数名|
  変数名.validates :カラム名, ヘルパー
  変数名.validates :カラム名, ヘルパー
end

このように指定します。

モデル
1
2
3
4
with_options if: :user_signed_in? do |user|
  user.validates :name, presence: true
  user.validates :age, presence: true
end

バリデーションの流れ
リンクをコピーしました

検証された結果、入力必須なのに値がなかったので保存時にROLLBACKがかかり、保存されません。

ターミナル
1
2
3
4
  User Load (0.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1  ORDER BY `users`.`id` ASC LIMIT 1
  User Load (0.8ms)  SELECT `users`.* FROM `users`
   (0.1ms)  BEGIN
   (5.5ms)  ROLLBACK

このようにターミナルのログを確認するとバリデーションに引っかかって、保存されないことが確認できます。

予期しないエラーが起きてdebugする場合
リンクをコピーしました

データが保存される際、こちらが予期しない理由で検証が行われ、データが保存されずROLLBACKされてしまう場合があります。
この時にどういう理由でROLLBACKされてしまうのか原因を探る必要があります。

その際に使うメソッドが先ほど紹介したvalid?メソッドです。

今回は投稿フォームにちゃんと登録をしたのにも関わらず登録ができない時の例をみてみましょう。

登録できない例

ちゃんと値を入力しているのに保存ができない理由がなぜだかわかりません。

ターミナル
1
2
3
4
5
6
7
8
Processing by UsersController#create as HTML
  Parameters: {
# 中略
"user"=>{"name"=>"管理人", "sex"=>"男", "age"=>"55", "tall"=>"167", "weight"=>"45"}, "commit"=>"送信"}
   (0.9ms)  BEGIN
  ↳ app/controllers/users_controller.rb:11
   (0.2ms)  ROLLBACK
  ↳ app/controllers/users_controller.rb:11

このように予期せぬエラーが起きたときにどうやってデバッグするか、エラーの原因を調査する流れを説明していきます。

今回のモデルの記述は下記のようになっています。

user.rb
1
2
3
4
class User < ApplicationRecord
    validates :name, presence: true
    belongs_to :job
end

バリデーションはnameカラムが入力必須ということしか定義していません。
今回はちゃんとnameカラムに値が入力されているのになぜか検証で引っかかってしまいました。

理由がわからないので、まずはcreateアクション内でbinding.pryを使い処理を止めます。
次に保存するインスタンスにvalid?メソッドで検証が行われて保存できる状態か、できない状態かを調べます。
返り値がfalseなので検証で保存できない状態だということが確認できました。

ターミナル
1
2
[1] pry(main)> @user.valid?
=> false

valid?メソッドを使用するとそのインスタンスがerrorsメソッドを使用した時にエラーメッセージを確認することができるようになります。
では実際どんなエラーメッセージが出ているか確認してみます。

ターミナル
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[2] pry(main)> @user.errors
=> #<ActiveModel::Errors:0x007fdcb2db3620
 @base=
  #<User:0x007fd522d08870
   id: nil,
   name: "管理人",
   job_id: nil,
   sex: "男",
   age: 55,
   tall: 167.0,
   weight: 45.0,
   created_at: nil,
   updated_at: nil>,
 @details={:job=>[{:error=>:blank}]},
 @messages={:job=>["must exist"]}>

このように「must exist」というメッセージが確認できました。
このメッセージは「jobカラムの値が存在しなければならない」という意味です。
今回は存在しないjobカラムに対するエラーが表示されました。

色々調べるとrails5からアソシエーションを定義しているとusersテーブルとjobsテーブルとの結びつけをするjob_idというカラムにデフォルトで入力必須のバリデーションが定義されてしまうためだということがわかりました。
この場合アソシエーションの定義であるbelongs_toのバリデーションに引っかかるとjob_idではなく、モデル名であるjobがエラーメッセージ内に表示されるようです。

外部キーのバリデーション
リンクをコピーしました

Rails4まではアソシエーションを定義した時のbelongs_toの外部キーでnilを許可しないように「belongs_to :user, required: true」などのバリデーションを手動で定義していました。
ですが、rails5からは自動でnilを許可しないバリデーションが定義されるようになりました。
これを意図的に外すには下記のように定義します。

モデル
1
belongs_to :user, optional: true

このように自動でnilを許可しないバリデーションが定義されているので、投稿フォームに職業を登録するフォームを追加し、job_idも保存できるようにすることによって今回のエラーを解決することができました。

フォームを変更

このようにvalid?メソッドとerrorsメソッドを使用することで原因を特定することができます。

もしvalid?メソッドを使用していないインスタンスにerrorsメソッドを使用すると下記のようにmessageの部分は何も入っていない状態になってしまい、エラーメッセージが確認できません。

ターミナル
1
2
3
4
5
6
7
8
9
10
11
12
13
14
=> #<ActiveModel::Errors:0x007fcb3ceb9c68
 @base=
  #<User:0x007fcb3e594848
   id: nil,
   name: "ピカわか",
   job_id: 5,
   sex: 0,
   age: 25,
   tall: 170.0,
   weight: 85.0,
   created_at: nil,
   updated_at: nil>,
 @details={},
 @messages={}>

もし原因不明でROLLBACKが起きて値を保存できない場合は、valid?メソッドとerrorsメソッドを利用して原因を確認してみましょう。

意図的にエラーを起こす場合
リンクをコピーしました

データを保存する際、保存できた時とできなかった時で処理を分けたい場合があります。
データを保存するメソッドにcreateとsaveメソッドがありますが、saveメソッドを使うと検証で引っかかった時にfalseが返ります。
これはvalid?メソッドを使った時と同じことをsaveメソッドが行なっているからです。

ターミナル
1
2
3
4
5
6
7
8
9
10
11
[1] pry(main)> article = Article.new(text: "")
=> #<Article:0x007fc5b8079830
 id: nil,
 text: "",
 created_at: nil,
 updated_at: nil,
 user_id: nil>
[2] pry(main)> article.save
   (132.4ms)  BEGIN
   (8.2ms)  ROLLBACK
=> false

valid?メソッドを使った時と同じことをsaveメソッドが行なっているということはsaveメソッドを使っても、errorsメソッドを使用した時にエラーメッセージを確認することができます。

ターミナル
1
2
3
4
5
6
7
8
9
10
[3] pry(main)> article.errors
=> #<ActiveModel::Errors:0x007fc5b8020118
 @base=
  #<Article:0x007fc5b8079830
   id: nil,
   text: "",
   created_at: nil,
   updated_at: nil,
   user_id: nil>,
 @messages={:text=>["can't be blank"]}>

そして検証で引っかかるとfalseが返るのでコントローラーでは下記のように条件分岐をさせることができます。

コントローラー
1
2
3
4
5
6
7
def create
  @article = Article.new(article_params)
  if @article.save
    redirect_to root_path and return
  end
  render :new
end

ここでは保存がされればルートパスへ、保存が失敗すればもう一度投稿フォームが表示されるよう記述しています。

またデータベースに保存されなかった時に、ユーザーにエラーが出て保存がされなかったことをメッセージで知らせることができます。
その時に使うメソッドがerrors.any?メソッドです。
もしエラーが出て保存されない場合、返り値としてtrueが返ります。
それを利用してビューファイルには下記のように記述をします。

ビューファイル
1
2
3
<% if @article.errors.any? %>
   <p class="red">名前を入力してください</p>
<% end %>

バリデーション

こうすることにより、ユーザーに保存ができなかったことを知らせることができます。

カスタムバリデーションを作ろう
リンクをコピーしました

今まで紹介してきた中に自分が実行したいバリデーションがない場合は自分で条件を作成することができます。
そのことをカスタムバリデーションと呼びます。
では実際に自分でバリデーションを定義する流れをみていきましょう。

まずはappフォルダ内にvalidatorsフォルダを作成します。
validatorsフォルダ内にはカスタムバリデーションを定義するファイルを作成します。
この時のファイル名はバリデーション名にしておきましょう。

次にそのファイルに下記のようなコードを記述します。

バリデーション名.rb
1
2
3
4
5
class バリデーション名Validator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    検証する内容
  end
end

カスタムバリデーションを作成する際にはvalidate_eachメソッドを使用します。
3つの引数は順番に(保存するテーブルのレコード, カラム名, 値)を表します。

実際には下記のように記述します。

app/validators/name_check.rb
1
2
3
4
5
6
7
class NameCheckValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value == "管理人"
      record.errors[attribute] << "その名前は使用できません"
    end
  end
end

次にこのバリデーションを有効にするためconfig/application.rbにカスタムバリデーションを定義したファイルがあるフォルダのパスを下記のように追加します。

config/application.rb
1
2
3
4
5
module アプリ名
  class Application < Rails::Application
    config.autoload_paths += Dir["#{config.root}/app/validators"]
  end
end

使用する時には下記のように記述します。
上の例だとバリデーション名を「NameCheck」としているのでname_checkという形で使用します。

モデル
1
validates :user, name_check: true

validateメソッドを使った方法
リンクをコピーしました

他にもvalidateメソッドを使用してバリデーションを作成することもできます。
「validates」のように「s」が付かないので気をつけましょう。

モデル
1
2
3
4
5
validate :メソッド名

def メソッド名
  検証したいコード
end

実際は下記のように定義します。

モデル
1
2
3
4
5
6
7
validate :check_name

def check_name
  if name == "管理人"
    errors.add(:name, "その名前は使用できません")
  end
end

一時的なバリデーションのスキップ方法
リンクをコピーしました

一時的に検証を行わないようにするには下記のように記述します。

コントローラー
1
メソッド(validate: false)

下記のように使います。

ターミナル
1
2
3
4
5
6
7
article = Arrticle.new(title: "")
article.save(validate: false)
# 検証がスキップされるので保存が実行される
(1.1ms)  BEGIN
  Arrticle Create (54.9ms)  INSERT INTO `articles` (`title`, `created_at`, `updated_at`) VALUES ('', '20XX-XX-XX XX:XX:XX', '20XX-XX-XX XX:XX:XX')
   (26.7ms)  COMMIT
=> true

ただし思わぬバグが発生することがあるので、使う際は十分に注意しましょう。

まとめ

・バリデーションとはデータベースにデータを保存するときに内容を検証してくれる機能です。
・ヘルパーを使うことで色々な検証を行うことができます。
・valid?メソッドとerrorsメソッドを使えばどの検証に引っかかっているかを確認することができます。
・カスタムバリデーションで自分で作成した検証を行うことができます。