• WebCamp_インタビュー
    「自信の持てるスキルを得たい!」内定辞退した女子大生がプログラミングを学習したワケ。
    2018.04.28
  • WebCamp_インタビュー
    時間や場所にとらわれず自由に働くために必要なスキルとは?【WebCamp卒業生インタビュー】
    2018.01.26
  • WebCamp_インタビュー
    【卒業生インタビュー】台湾で月間100万UUの訪日旅行メディアを手掛けるCEOが、プログラミングを学んで得たものとは?
    2018.01.15
  • WebCamp_インタビュー
    “未経験”でもたった1ヶ月で営業からエンジニアとして転職!『WebCamp』受講者インタビュー
    2017.10.04
  • WebCamp_インタビュー
    【WebCamp卒業生インタビュー】1ヶ月でRubyをゼロから学び、Webエンジニアとして転職!
    2018.01.15
  • WebCampPro_インタビュー
    未経験でも寿司職人からWebデザイナーになった!ホスピタリティでスクールを支える宮脇トレーナー
    2017.05.26
  • WebCampPro_インタビュー
    自分で稼ぐ力をつけるため、新卒5年目の営業マンがエンジニアに転職!【WebCampPro転職者インタビュー】
    2018.02.02
  • WebCampPro_インタビュー
    未経験31歳からエンジニア転職を実現【実際に聞いてみた】
    2017.04.01
  • WebCamp_インタビュー
    「1カ月頑張ればこの先が見えてくる」地元メディアを立ち上げたママさん
    2017.07.20
  • WebCampPro_インタビュー
    未経験から上京し、エンジニアとしてチームラボグループに転職!【WebCampPro卒業生インタビュー】
    2018.03.10
  • WebCamp_インタビュー
    【WebCamp受講生インタビュー】起業準備中にCEOが気がついたプログラミングスキルの重要性とは?
    2017.12.25

◆当サイトで人気のプログラミング教室のおすすめランキングはこちら!
プログラミングは独学では非効率で、時間を無駄にするリスクがあります。効率的なカリキュラムで学べるスクールを受講しましょう。

Web Camp【マンツーマンサポート】1ヶ月短期集中でプログラミングを学ぶスクール
1ヶ月通い放題・メンター常駐の教室環境でWebサービス等作りたい方
TechAcademyオンラインで開講しているプログラミングスクール
オンラインでどこでも学べる!/教室に行くのが忙しい人でも安心!
Tech Camp教養としてのITスキルを学べるスクール
Webデザイン/AI(人工知能)/IOS/Androidアプリ制作/VRを学びたい方!
WebCampPro転職保証付き!エンジニアとして転職したい人におすすめ!
未経験からプロのエンジニアを3ヶ月で目指すプログラミングスクールです。
11月生募集中!当社人気の転職保証コース
プログラミング学習から転職成功まで導く、当社人気のWebCamp Proコース。
10月生は満員となっております。11月生募集に向け、お早めの申込みをオススメします。
プログラミング未経験でもエンジニア転職を絶対成功させたい
スキルを身に着けて人生を自ら切り開きたい
上記にあてはまる方は、ぜひご検討ください!

はじめに

「データの正しさ」を意識したことはあるでしょうか?

Webアプリケーションは、ユーザーとやりとりして多くの情報を受け取り、それに従って処理を行います。

そのため、受け取るデータが、処理できる形式のものであるかどうかを確認するのは、とても重要です。

特にユーザーが入力するデータは、全角半角や桁数、入力漏れ、入力項目違いなど、入力ミスがある可能性が十分に考えられます。

それらの「間違ったデータ」を最初に見つけて「正しいデータ」にしておくことで、その後の処理を実装するための検討内容を少なくし、余計な手数やバグを防ぐことができるでしょう。

今回は、そんな「データの正しさ」を検証することができるValidationsについて、解説します。

RailsのValidationsを知る

RailsのValidationsは、与えられたデータ(オブジェクト)が、その後の処理に適したものかどうかを確認するための検証処理です。

例えば、ユーザー情報の入力で、電話番号や郵便番号欄に半角の数字とハイフン以外の文字があったり、メールアドレスに全角文字が使われていたりされていると、その後の処理でいちいち変換する必要が出てきます。

そのため、最初の入力時に、適していない入力があった場合にエラー表示するなどして、再入力を求めるなど動作をするなどした方が、効率的です。

そういった「データが最適かどうかのチェックをする」のが、バリデーション(Validations)なのです。

Validationのタイミング

検証を行うタイミングは、それほど多くはありません。

なぜなら、あちこちで検証をするのではなく、できる限り同じタイミングで処理した方が、メンテナンス性や拡張性が高くなるからです。

例えば、ユーザーデータを登録して、それをもとに最適な情報を表示するプログラムを考えてみましょう。

一般的に、以下のようなフローになります。

 1.ユーザーフォームへのデータ入力(ユーザーが手で入力)

2.データをデータベースへ登録

3.データベースからユーザーデータを取得

4.取得したユーザーデータを解析

5.解析結果から情報を取得して表示

上記のフローで、検証を行えるタイミングは、次の4カ所です。
・1.の直後
・2.の直前
・3.の直後
・4.の直前

仮に、「1.の直後」に検証処理をしていれば、それ以降は「データが正しい」ことが補償されていますので、以降の処理では検証する必要がありません。逆に言えば、以降の処理は「データの形式は正しい」という前提のもとに作成することができますので、検討するパターンが減り、効率の良い実装ができます。

そのため、「1.の直後」である、ユーザーがデータを入力した直後のタイミングに検証処理を実行して、間違っていれば修正させる(正しいものしか入力できない)ようにするのが、最適解になります。

ただし、もしデータ入力がユーザー入力以外にもある場合は、どうでしょうか? 例えば、他のサービスや事前登録したファイルから取り込むなどというのは、良くあることです。

その場合、1.の処理が数種類存在することになりますので、そのすべてに同じ検証処理を実装するのは効率が良くありません。そのため、そういった場合は、「2.の直前」で検証するのが最適でしょう。「2.の直前」に検証し、正しいデータだけデータベースに登録することで、データベースに登録されているデータが正しいものであると補償されます。そのため、その後の処理はデータが正しいことを前提にして処理を進めれば良いわけです。

しかし、作成したWebアプリケーションの管理下にある特定のデータベース以外からデータを取得する可能性がある場合は、データベースからデータを取得した直後である「3.の直後」に検証しておかなければいけません。

そして、そもそもユーザーデータを解析して表示する処理を外部APIで提供するなど、汎用的なものとするのであれば、「4.の直前」である解析処理の直前に検証することで、正しいデータの場合だけ処理する必要があります。

もちろん、複数箇所で検証を行っても問題はありませんが、明らかに「正しいデータしか来ない」タイミングで検証するのは、作成時、実行時ともに無駄な動きになります。

このように、検証を行うタイミングは、「どこから来てどう渡されていくのか」というデータの流れを整理してから考えなければいけません。どのタイミングで検証すれば、検証漏れがないのかをしっかりと考慮して、検証処理を使っていきましょう。

基本的な使い方

ここからは、検証を実行するための方法を説明します。

Railsで用意されている検証処理を実行する方法は、データベースへのアクセス直前(2.の直前)の方法と、任意の箇所の2種類が準備されています。

データベースへのアクセス直前

以下のデータベースアクセス用のメソッド(Active Recordオブジェクトのメソッド)では、内部的に検証を実行してからデータベースへの登録などを行います。これは、「2.の直前」のタイミングで検証しているということになります。

メソッド メソッドの意味 検証結果が
falseの場合の戻り値
create 新しいレコードを生成して保存する オブジェクトそのもの
create! createの破壊的メソッド 例外が発生
save レコードを保存する
既存のレコードを別レコードとして保存する、もしくはnewで生成したレコードを保存する
false
save! saveの破壊的メソッド 例外が発生
update オブジェクトを変更して保存する false
update! updateの破壊的メソッド 例外が発生

これらのメソッドでは、検証結果がtrue(正しいデータ)の場合だけデータベースへデータを保存(変更)し、false(間違ったデータ)の場合は保存しません。

ただし、以下のように引数として「validate: false」を渡すことで、検証を実行しないようにすることが可能です。(あまり推奨されません)

save(validate: false)

また、以下のメソッドでは検証が実行されませんので、注意が必要です。

メソッド 説明
decrement! カラムのデータを指定された値だけ減ずる(数値データにのみ有効)
v2.3.8以前
decrement_counter カラムのデータを-1する(数値データにのみ有効)
increment! カラムのデータを指定された値だけ加算する(数値データにのみ有効)
v2.3.8以前
increment_counter カラムのデータを+1する(数値データにのみ有効)
toggle! trueとfalseを入れ替える
touch 更新日時(update_at)を現在時刻に書き換える
update_all 指定された条件に一致するレコードをすべて更新する
update_attribute 指定したカラムのデータを更新する
update_column 指定したカラムのデータを更新する
update_columns 複数の指定したカラムのデータを更新する
update_counters 指定したカラムを+1もしくは-1する
v2.3.8以前

任意の場所での実行

前述のように、データベースへのアクセス直前に検証が実行されない場合などもありますので、Railsには、別途、検証を実行させる方法も準備されています。

それが、「valid?メソッド」もしくは「invalid?メソッド」です。

それぞれ、以下のように利用することで、検証した結果がtrueもしくはfalseで返ってきます。その結果を基に、その後の処理をどうするか分岐させれば良いわけです。

ActiveRecordオブジェクト.valid?
ActiveRecordオブジェクト.invalid?

valid?メソッドは、正しいデータだった場合はtrue、適していないデータの場合はfalseを返してきます。invalid?メソッドは、その逆の戻り値が返ってきます。

検証結果の確認

検証を実施した結果、もしエラーが発生していた場合、どのカラムでどんなエラーが発生したのか(エラーメッセージ)を取得することができます。

ActiveRecordオブジェクト.errors

errorsメソッドを利用すると、次のようなエラーが発生したカラムと発生したエラーメッセージのハッシュが返ってきますので、valid?メソッドなどの利用時にメッセージ表示するなど活用できるでしょう。

{ カラム名:[エラーメッセージ] }

コツコツ独学×スクールで実践。未経験からエンジニアに転職!【WebCamp卒業生インタビュー】
2018-03-22 23:28
今回の記事では、独学でPHPを1年半学習し、その後WebCampを受講して未経験からエンジニアへと転職された佐々木さんにお話を伺いました。 <プロフィール> 佐々木 祐樹 さん(2...

検証処理(Validator)の内容

では、ここから具体的な検証処理の内容を説明していきましょう。

Railsには、バリデーションヘルパーと呼ばれる標準で搭載された検証処理があり、多くの場合、その組み合わせだけで必要な検証を行うことができるようになっています。

また、もちろんですが自分で作成することも可能になっていますので、それも合わせて紹介します。

バリデーションヘルパー

Railsに標準搭載されているValidationであるバリデーションヘルパーを紹介します。

ここで紹介するヘルパーは、すべて複数のカラムに対して検証を行えますので、効率的な検証が行えます。また、オプションを利用することで、必要十分なカスタマイズが可能になっています。

バリデーションヘルパーを使用するためには、ActiveRecordのモデル(ApplicationRecordクラスのサブクラス)に、validatesメソッドを使って次のようにして記載します。

class モデル名 < ApplicationRecord
  validates :カラム名, バリデーションヘルパー名: true
end

class モデル名 < ApplicationRecord
  validates :カラム名, バリデーションヘルパー名: { オプション,,, }
end

現時点(v5.2.1時点)で利用できるバリデーションヘルパーは、以下のようになっています。

バリデーションヘルパー 検証内容 備考
acceptance フォーム上のチェックボックスがオンになっている データベース上にカラムがなくても検証可能。もしカラムがある場合は、acceptオプションを設定するか、true設定しておくこと
validates_associated 他のモデルと関連付けられており、両方のモデルの検証を行う必要がある場合に使用する ・両方のモデルに設定すると無限ループに陥るので、必ず片方だけに設定すること
・validatesメソッドを使用せず、以下のように使用する
validates_associated :関連付けられたモデル名
confirmation 2つのテキストフィールドが一致している フォーム上の2つのテキストフィールドを比較するが、フィールド名として片方はデータベース上のカラム名、もう一方は仮想のカラムでカラム名_confirmationとすること
カラム名_confirmationがnilの場合は検証されない
・case_sensitiveオプションをfalseにすることで、大文字小文字を区別せずに比較可能
exclusion inオプションで与えられたenumerableオブジェクトにカラムの値が含まれていない inオプションの代わりに別名のwithinオプションも使用可能
format withオプションで与えられた正規表現とカラムの値がマッチする
inclusion inオプションで与えられたenumerableオブジェクトにカラムの値が含まれている inオプションの代わりに別名のwithinオプションも使用可能
length カラムの値の文字数がオプションの範囲内 以下のオプションを使用可能
・minimum:指定された値以上
・maximum:指定された値以下
・inまたはwithin:指定された範囲内(例:2..20)
・is:指定された値と等しい
numericality カラムの値が整数または浮動小数点である 通常は、カラムがnilの場合、エラーが発生する
以下のオプションを使用可能
・greater_than:指定された値よりも大きい
・greater_than_or_equal_to:指定された値以上
・equal_to:指定された値と等しい
・less_than:指定された値よりも小さい
・less_than_or_equal_to:指定された値以下
・other_than:指定した値以外
・odd:trueに設定されている場合は、奇数であること
・even:trueに設定されている場合は、偶数であること
・only_integer:trueに設定されている場合は、整数であること
presence カラムの値がnilや空文字ではない 真偽値に対しては、正しい結果が得られない(falseは空文字と判断されるため)
真偽値の存在をチェックする場合は、inclusionを使用すること
absence カラムの値がnilや空文字である 真偽値に対しては、正しい結果が得られない
真偽値の存在をチェックする場合は、exclusionを使用すること
uniqueness モデルのテーブルに対して、そのカラムの値と同じ値を持つ既存のレコードがない ・case_sensitive:falseにすることで、大文字小文字を区別せずに比較可能
・scope:ここに指定したカラムと組み合わせて検証する
validates_with Validationに使用するクラス、クラスのリストを指定する
自作のValidationを利用する場合に使用する
validatesメソッドを使用せず、以下のように使用する
validates_with :クラス名
validates_each 指定したカラムを検証するブロックを設定する validatesメソッドを使用せず、以下のように使用する

validates_each :カラム名 do |ブロック引数1, ブロック引数2, ブロック引数3|
検証処理と検証失敗時のエラーメッセージの追加処理
end

ブロック引数には、ActiveRecordレコードオブジェクト、カラム名、カラムの値が渡される
エラーメッセージの追加は、ActiveRecordオブジェクト.errors.addメソッドを使用する

これらのバリデーションヘルパーを組み合わせることで、ほとんどの場合のデータ検証を行うことが可能になるでしょう。

検証処理をカスタマイズする共通オプション

また、以下のオプションは上記すべてで使用できるものです。これらを利用することで、より柔軟な検証が可能になります。(ヘルパー特有のオプションは、上記の備考欄を参照してください)

オプション 内容
allow_nil カラムの値がnilの場合、検証をスキップする
allow_blank カラムの値がnilと空文字(blank?がtrue)の場合、検証をスキップする
message デフォルト設定以外のエラーメッセージを登録する
メッセージには、%{value}、%{attribute}、%{model}を含めることができるが、この通りの記載にすること(空白を入れるのも不可)
on 検証が自動実行される場合の実行タイミングを指定する
例):createを指定すれば、レコードの新規作成時のみ検証される
strict 検証に失敗した場合、例外(ActiveModel::StrictValidationFailed)を発生させる
if 特定の条件のときのみ、検証を実行する
unless 特定の条件出ないときに、検証を実行する

“未経験”でもたった1ヶ月で営業からエンジニアとして転職!『WebCamp』受講者インタビュー
2017-10-04 10:26
今回の記事では、未経験からWebCampを1ヶ月受講し、その後エンジニアとして転職をした喜田さんにお話を伺いました。 <プロフィール> 喜田 大介 さん (28歳) 大学時代はプ...

カスタムバリデータ(オリジナルのValidation)を作る

前述で紹介したバリデーションヘルパーでは、どうしても実現できない検証を行いたい場合もあります。そんな場合は、自作のValidationを作ることも可能です。

なお、カスタムバリデータの実行には、すでに紹介しているバリデーションヘルパー「validates_with」を使ってレコードを渡す必要がありますので、呼び出し方法も含めて紹介しましょう。

カスタムバリデータの定義(検証対象のカラム名が決まっている場合)

特定のカラムを検証するカスタムバリデータを作成する場合は、ActiveModel::Validatorを継承するクラスを定義し、そこにvalidateメソッドを実装します。

基本的には以下のようになるでしょう。

# カスタムバリデータの追加
class バリデータ名 < ActiveModel::Validator
  def validate(ActiveRecordオブジェクト)
    unless ActiveRecordオブジェクト.カラム名を使った条件
      record.errors[カラム名] << 'エラーメッセージ' # エラーメッセージを追加する
    end
  end
end

#モデルでの呼び出し
class モデル名 < ApplicationRecord
  include ActiveModel::Validations
  validates_with バリデータ名
end

カラム名が決まっている専用バリデータのため、シンプルなプログラムコードになります。ただし、この方法は、汎用的なカラムの検証を行うのに不向きです。

また、この方法で定義されたバリデータは、最初の実行時に初期化された後、初期化されることはありません。更新されるインスタンス変数を使った処理を行っている場合は、実行の都度、明示的に初期化処理を行うなど、注意して扱わなければいけません。

カスタムバリデータの定義(検証対象のカラム名が不定な場合)

Railsには、カラム名を引数として渡すことで、汎用的に利用できるカスタムバリデータを作る方法も提供されています。

そのためには、ActiveModel::EachValidatorを継承するクラスを定義して、validate_eachメソッドを実装しましょう。このとき、validate_eachメソッドの引数として、(ActiveRecordオブジェクト、カラム名、カラムの値)が渡されますので、呼び出し側が任意の対象を設定できるわけです。

一般的には、以下のような定義と使用方法になります。

# カスタムバリデータの追加
class バリデータ名Validator < ActiveModel::EachValidator
  def validate_each(ActiveRecordオブジェクト,カラム名,カラムの値)
    unless カラムの値を使った条件
      record.errors[カラム名] << 'エラーメッセージ' # エラーメッセージを追加する
    end
  end
end

#モデルでの呼び出し
class モデル名 < ApplicationRecord
  validates :カラム名, バリデータ名: true, バリデーションヘルパー名: true,,,  # バリデーションヘルパーを同時に設定することも可能(1)
end

※(1)で「バリデータ名」を記載することで、定義している「バリデータ名Validator」を利用することを宣言することになります。例えば、「NameValidator」の場合は「name」になります。

カスタムバリデータを別ファイルで定義した場合

ほとんどの場合、カスタムバリデータをモデル内で定義することはなく、カスタムバリデータ用のディレクトリを作って、別のファイルに定義することでしょう。その場合は、定義したファイルを読み込んでやる必要がありますので、注意が必要です。

カスタムバリデータを定義したファイルが、「/app/validators」というディレクトリに格納されている場合、「config/application.rb」に追記します。

module Core
  class Application < Rails::Application
    :
    :
    config.autoload_paths += Dir["#{config.root}/app/validators"]  # カスタムバリデータを自動で読み込むようにする
    :
    :
 end
end

以上の追記を行うことで、アプリケーション起動時にカスタムバリデータが読み込まれます。

未経験から上京し、エンジニアとしてチームラボグループに転職!【WebCampPro卒業生インタビュー】
2018-03-10 14:42
今回の記事では、たまたま見たテレビ番組がきっかけでエンジニアに興味を持ち、WebCampProを受講して見事転職を決めた中村さんにインタビューしました。 <プロフィール> 中村 駿...

まとめ

RailsのValidationsについて、解説しました。

データの整合性を保障するValidationは、Railsのプログラムの効率を上げ、思わぬバグを防ぐのに、非常に効果があります。

ただし、どんなタイミングで検証するかによって、検証漏れや余計な検証を行うことがありますし、メンテナンス性が悪くなります。

Validationのタイミングを考えるには、Railsアプリケーション全体の処理の流れやデータがどこからきてどう利用されるかをしっかりと考慮しなければいけません。

しかし、それらを考慮できるということは、アプリケーション全体を把握できているということです。そうなれば、Railsプログラマー中級者への扉が開いたと思って間違いありません。


・RailsのValidationsは、与えられたデータ(オブジェクト)が、その後の処理に適したものかどうかを確認するための処理
・データが入力された直後がもっとも効率の良い検証タイミング
・検証タイミングは、データがどこからきてどう処理されるのか、処理をどこまで再利用するのかを考慮する必要がある
・標準搭載されている検証処理をバリデーションヘルパーと呼ぶ

WebCampOnline プログラミングコースについて

WebCampでは、「どこでも学べる」オンラインコースを開講しています。

初心者・未経験の方でもわずか1ヶ月でプログラミングの基礎を学び、アプリケーション開発をすることができます。

WebCampOnlineが選ばれる3つの理由

1.学習の仕方がわからなくても安心!初心者に寄り添った学習カリキュラム

これから学習を始める初心者の方や、独学で挫折してしまった方に向けて、アプリケーション作成をゴールとする一気通貫したカリキュラムを提供しています。2500名を輩出しているWebCampだからこその教室でのリアルな受講生の声を反映し、オンラインコースでも初心者に寄り添った学習体験をご提供いたします。

2.つまずいたらすぐ解決!プロのエンジニアに質問し放題

プログラミング学習で挫折する理由の多くは「つまずいた時に聞ける人がいない」ことです。オンラインコースでは、現役エンジニアやプロ講師に、すぐにチャットでの質問が可能です。つまずきをすぐに解消できるので、挫折せずに学習を継続することができます

3.1ヶ月間で終わらなくても大丈夫!カリキュラムは"卒業後"も"無料"で利用可能

受講したいけど、仕事が急に忙しくなるかもしれないから受講するか迷っている・・・そんな方も多いのではないでしょうか?ご安心ください。カリキュラムは期間終了後も「無料」で使うことができます。また、しっかり学習時間を確保した方も、振り返って学習することでプログラミングスキルがご自身に馴染んできます。

▼まずは無料でWebデザインのカリキュラムを体験しよう!

【インタビュー】1ヶ月でRubyをゼロから学び、Webエンジニアとして転職!

ブラジルから帰国し技術をつけようとRubyエンジニアを目指してWebCampでRubyを学び、見事Webエンジニアとして転職を果たした田中さんにお話を伺いました。

Rubyの学習がしたい。基礎をしっかりと理解したい

転職のサポートがほしい

と考えている方はぜひお読み下さい。

【WebCamp卒業生インタビュー】1ヶ月でRubyをゼロから学び、Webエンジニアとして転職!
2018-01-15 13:23
今回の記事では、WebCampで1ヶ月間Rubyを学習し、Webエンジニアとして転職した卒業生の田中さんにお話を伺いました。 <プロフィール> 田中 デニス 昭彦さん(...
関連キーワード
Ruby on Railsの関連記事
  • 【Rails入門説明書】enumについて解説
  • 【Rails入門説明書】link_toについて解説
  • 【Rails入門説明書】Bootstrapについて解説
  • 【Rails入門説明書】scaffoldについて解説
  • 【Rails入門説明書】validationsについて解説
  • 【Rails入門説明書】routesについて解説
おすすめの記事