モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

目次目次を開く/閉じる

サーバ側で行うフォーム入力値のバリデーション (Rails4)

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2014/11/16
最終更新最終更新
2021/10/07
記事区分記事区分
一般公開

ユーザからの入力値チェックは、一般にクライアント側とサーバ側の両方で行います。クライアント側のチェックは、例えばブラウザのJavascriptによって行うことができます。これは悪意のないユーザの操作性向上のために行います。ここでは、悪意あるユーザがJavascriptを無効にして不正なデータを送信してきた場合などに備えサーバ側でチェックを行うためのRailsのバリデーション機能の使用方法を記載します。

サンプルアプリの準備

サンプルアプリを作成します。

$ rails new myApp
$ cd myApp/
$ rails generate scaffold myModel field1:string field2:integer field3:date field4:boolean
$ rake db:migrate
$ rails s

http://localhost:3000/my_models/

バリデーション機能を実際に使用してみる

モデル app/models/my_model.rb に各フィールドが満たすべき条件を記述します。

class MyModel < ActiveRecord::Base
  validates :field1,
    presence: true   # 値が空を許さない
  validates :field2,
    presence: true   # 値が空を許さない
end

MyModelのモデルインスタンスについて、コントローラで以下の記述が可能です。field1 または field2 に値がセットされていない場合は false が返されます。

  • @my_model.save
  • @my_model.update(my_model_params)
  • @my_model.valid?

バリデーションに失敗した場合はそのエラー内容がモデルインスタンスに格納されます。以下のようにしてビューで参照できます。

app/views/my_models/_form.html.erb (scaffoldで自動生成されたファイル)

<%= form_for(@my_model) do |f| %>
  <% if @my_model.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@my_model.errors.count, "error") %> prohibited this my_model from being saved:</h2>

      <ul>
      <% @my_model.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  ...
<% end %>

デザインのためのCSSは例えば以下のように指定できます。

app/assets/stylesheets/scaffolds.css.scss (scaffoldで自動生成されたファイル)

.field_with_errors { /* エラーのあったフォームの前後には */
  padding: 2px;      /* field_with_errors クラスの div タグが自動生成されます (後述) */
  background-color: red;
  display: table;
}

#error_explanation { /* ↑の form_for... のデザイン */
  width: 450px;
  border: 2px solid red;
  padding: 7px;
  padding-bottom: 0;
  margin-bottom: 20px;
  background-color: #f0f0f0;
  h2 {
    text-align: left;
    font-weight: bold;
    padding: 5px 5px 5px 15px;
    font-size: 12px;
    margin: -7px;
    margin-bottom: 0px;
    background-color: #c00;
    color: #fff;
  }
  ul li {
    font-size: 12px;
    list-style: square;
  }
}

エラーのあったフォームの前後には field_with_errors クラスの div タグが自動生成されます。

<div class="field">
  <div class="field_with_errors"><label for="my_model_field1">Field1</label></div><br>
  <div class="field_with_errors"><input type="text" value="" name="my_model[field1]" id="my_model_field1"></div>
</div>

Railsに用意されている基本的なバリデーションパターン

何らかの値が入力されたことを検証

基本形

class MyModel < ActiveRecord::Base
  validates :field1,
    presence: true
end

複数のフィールドに対して同じ条件を指定 ('presence' に限らない記法です)

class MyModel < ActiveRecord::Base
  validates :field1, :field2,
    presence: true
end

エラー時のメッセージ (@my_model.errors.full_messages) をカスタマイズ

class MyModel < ActiveRecord::Base
  validates :field1,
    presence: { message: I18n.locale == :ja ? 'は必須項目です' : 'needs to be set.' }
end

補足

これは、以下のようにすることもできます。

class MyModel < ActiveRecord::Base
  validates :field1,
    presence: { message: I18n.t('validation.presence') }
end

config/locale/ja.yml

ja:
  validation:
    presence: は必須項目です

config/locale/en.yml

en:
  validation:
    presence: needs to be set.

入力値の長さを検証

基本形

class MyModel < ActiveRecord::Base
  validates :field1,
    length: { is: 5 } # 5文字だけを許す (日本語も判別可能)
end

基本形 その2

class MyModel < ActiveRecord::Base
  validates :field1,
    length: { minimum: 1, maximum: 2 } # 1-2 文字
end

別の条件もANDで指定 ('length' に限らない記法です)

class MyModel < ActiveRecord::Base
  validates :field1,
    length: { is: 5 },
    presence: true
end

エラー時のメッセージ (@my_model.errors.full_messages) をカスタマイズ

class MyModel < ActiveRecord::Base
  validates :field1,
    length: { is: 5, message: '%{value} は %{count} 桁である必要があります' }
end

正規表現による検証

class MyModel < ActiveRecord::Base
  validates :field1,
    format: { with: /\Apattern\d+\z/ }
end

なお ^pattern\d+$ としてしまうと、複数行の以下のような文字列に合致してしまうので注意しましょう。

hoge
pattern123
  • \A : 文字列の先頭に合致 (改行直後は除く)
  • \z : 文字列の末尾に合致 (改行が続く場合は除く)

なお '\z' であって '\Z' ではないので注意しましょう。

pattern123
     ← ここ、改行されるだけで文字列を含まない (「\Apattern\d+\Z」は合致する)
  • \Z : 文字列の末尾に合致 (改行が続く場合は除く。ただし改行されるだけの上記のような文字列には合致)

数値の検証

上限を指定

class MyModel < ActiveRecord::Base
  validates :field1,
    numericality: { only_integer: true, less_than_or_equal_to: 10 } # 数値のみ。10以下
end

下限を指定

class MyModel < ActiveRecord::Base
  validates :field1,
    numericality: { only_integer: true, greater_than_or_equal_to: 10 } # 数値のみ。10以上
end

候補を含むかどうかの検証

含まれていることを検証

class MyModel < ActiveRecord::Base
  validates :field1,
    inclusion: { in: ['hoge1','hoge2'] }
end

含まれていないことを検証

class MyModel < ActiveRecord::Base
  validates :field1,
    exclusion: { in: ['hoge1','hoge2'] }
end

重複しているかどうかの検証

基本形

class MyModel < ActiveRecord::Base
  validates :field1,
    uniqueness: true  # 重複を許さない
end

大文字小文字を区別せずに一意であるかどうか (条件としてはより厳しくなる)

class MyModel < ActiveRecord::Base
  validates :field1,
    uniqueness: { case_sensitive: false }
end

メッセージを指定

class MyModel < ActiveRecord::Base
  validates :field1,
    uniqueness: { message: '%{value} は既に登録済みです' }
end

複数フィールドセットで考えた場合に一意であるかどうか

class MyModel < ActiveRecord::Base
  validates :field1,
    # field1に重複があったとしてもfield2が異なればよしとする
    uniqueness: { scope: :field2 }
end

ビューに仮想的なフィールドを追加する検証パターン

同じ値を二回入力させる検証

メールアドレスやパスワードなど、間違ってもらっては困る項目を、確認のため二回入力してもらい合致することを確認します。二回目の入力のために仮想的にフィールドを追加します。データベースへの追加は不要であることに注意してください。

app/views/my_models/_form.html.erb

  ...
  <div class="field">
    <%= f.label :field1 %><br>
    <%= f.text_field :field1 %>
  </div>

  <div class="field">                         ← これを追加
    <%= f.label :field1_confirmation %><br>   ←
    <%= f.text_field :field1_confirmation %>  ←
  </div>                                      ←
  ...

app/controllers/my_models_controller.rb

    ...
    # Never trust parameters from the scary internet, only allow the white list through.
    def my_model_params
      # 「:field1_confirmation」を追加
      params.require(:my_model).permit(:field1, :field1_confirmation, :field2, :field3, :field4)
    end
end

app/models/my_model.rb

class MyModel < ActiveRecord::Base
  validates :field1, confirmation: true
end

一時的に入力させるだけのフィールド

ユーザの同意などのために一時的に必要になるフィールドを設置できます。

app/views/my_models/_form.html.erb

  ...
  <div class="field">
    <%= f.label :terms_of_service %><br>
    <%= f.check_box :terms_of_service %>
  </div>
  ...

app/controllers/my_models_controller.rb

    ...
    # Never trust parameters from the scary internet, only allow the white list through.
    def my_model_params
      # 「:terms_of_service」を追加
      params.require(:my_model).permit(:field1, :field2, :field3, :field4, :terms_of_service)
    end
end

app/models/my_model.rb

class MyModel < ActiveRecord::Base
  validates :terms_of_service, acceptance: true
end

値がセットされていなければ検証を通りません。なお、値がフォーム側で指定されている場合はモデル側での対応が必要です。

app/views/my_models/_form.html.erb

  ...
  <div class="field">
    <%= f.label :terms_of_service %><br>
    <%= f.check_box :terms_of_service, {checked: true}, 'my_value' %>
  </div>
  ...

app/models/my_model.rb

class MyModel < ActiveRecord::Base
  validates :terms_of_service, acceptance: { accept: 'my_value'}
end

一時的に入力させるだけのフィールド (仮想モデルを新たに用意する方法)

仮想モデル用のフォームを新規に追加します。なお仮想モデルのためのDBテーブルは不要であることに注意してください。

app/views/my_models/_form.html.erb

<%= form_for(@my_model) do |f| %>
  ...
  <%= fields_for @my_virtual_model do |mvm_f| %>   ← これを追加
    <div class="field">                            ←
      <%= mvm_f.label :fieldA %>                   ←
      <%= mvm_f.text_field :fieldA %>              ←
    </div>                                         ←
  <% end %>                                        ←
  ...
<% end %>

app/models/my_virtual_model.rb (新規に作成した仮想モデル)

class MyVirtualModel
  include ActiveModel::Model
  attr_accessor :fieldA

  validates :fieldA,
    presence: true
end

app/controllers/my_models_controller.rb

class MyModelsController < ApplicationController
  ...
  # GET /my_models/new
  def new
    @my_model = MyModel.new
    @my_virtual_model = MyVirtualModel.new  # ← これを追記
  end

  # GET /my_models/1/edit
  def edit
    @my_virtual_model = MyVirtualModel.new  # ← これを追記
  end

  # POST /my_models
  # POST /my_models.json
  def create
    @my_model = MyModel.new(my_model_params)
    @my_virtual_model = MyVirtualModel.new(params[:my_virtual_model])

    if not @my_virtual_model.valid?  # ←↑ これを追記
      warn 'fieldA is not set.'
    end
    ...
  end

  # PATCH/PUT /my_models/1
  # PATCH/PUT /my_models/1.json
  def update
    @my_virtual_model = MyVirtualModel.new(params[:my_virtual_model])
    if not @my_virtual_model.valid?  # ←↑ これを追記
      warn 'fieldA is not set.'
    end
    ...
  end
  ...
end

検証をスキップする条件を指定する

値がセットされていなければ検証しない

そもそもフォームの項目がないなどの理由で値が nil の場合は検証せずに通します。

class MyModel < ActiveRecord::Base
  validates :field1,
    uniqueness: { allow_nil: true }
end

上記に加えて、空白 "\s*" である場合も検証をせずに通します。

class MyModel < ActiveRecord::Base
  validates :field1,
    uniqueness: { allow_blank: true }
end

これらは 'uniqueness' に限らない記法です。

指定されていないイベントでは検証しない

新規作成 (INSERT) の場合にのみ検証

class MyModel < ActiveRecord::Base
  validates :field1,
    acceptance: { on: :create }
end

更新 (UPDATE) の場合にのみ検証

class MyModel < ActiveRecord::Base
  validates :field1,
    acceptance: { on: :update }
end

いずれの場合にも検証 (既定値です)

class MyModel < ActiveRecord::Base
  validates :field1,
    acceptance: { on: :save }
end

これらは 'acceptance' に限らない記法です。

検証を行う条件を if 文で指定

if (または unless) によって検証を行う場合を指定できます。

基本形

class MyModel < ActiveRecord::Base
  # field2 の値が 10 の場合のみ検証
  validates :field1,
    length: { is: 5, if: 'field2 == 10' }
end

基本形 その2

class MyModel < ActiveRecord::Base
  # field2 が空欄の場合にのみ検証
  validates :field1,
    length: { is: 5, if: 'field2.blank?' }
end

関数化

class MyModel < ActiveRecord::Base
  # field2 が空欄の場合にのみ検証
  validates :field1,
    length: { is: 5, if: 'field2_is_blank?' }

  private
  def field2_is_blank?
    field2.blank?
  end
end

独自の検証パターンを追加する

モデルに特化した検証パターン

あるモデルに特有の検証パターンであれば、汎用性は低くなりますが直接モデルファイルに記述すればよいです。

app/models/my_model.rb

class MyModel < ActiveRecord::Base
  validate :my_1_valid?, :my_2_valid?

  private
  def my_1_valid?
    errors.add(:field1, 'is invalid') if field1 == 'my_value1'
  end

  def my_2_valid?
    errors.add(:field1, 'is invalid') if field1 == 'my_value2'
  end
end

モデルに依存しない検証パターン

汎用的な検証パターンを作成するためには、専用の検証クラスを新規で作成します。

オプション指定が不要で、他のフィールド値も不要な検証

app/models/my_model.rb

class MyModel < ActiveRecord::Base
  validates :field1,
    sample: true
end

app/models/sample_validator.rb (新規作成したファイル)

class SampleValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.errors.add(attribute, 'is invalid') if not value == 'my_value'
  end
end

オプション指定が可能な検証

app/models/my_model.rb

class MyModel < ActiveRecord::Base
  validates :field1,
    sample2: { my_option: true }
    # sample2: true  # ← オプションを指定しない場合はこうします
end

app/models/sample2_validator.rb

class Sample2Validator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if options[:my_option]  # オプション指定がなされた場合
      my_value = 'hoge1'
    else               # オプション指定がなされなかった場合
      my_value = 'hoge2'
    end
    record.errors.add(attribute, 'is invalid') if not value == my_value
  end
end

他のフィールド値が必要な検証

app/models/my_model.rb

class MyModel < ActiveRecord::Base
  validates :field1,
    sample3: { other_field: 'field2' }
end

app/models/sample3_validator.rb

class Sample3Validator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    value_of_other_field = record.attributes[options[:other_field]]
    record.errors.add(attribute, 'is invalid') if not value_of_other_field == 123
  end
end
Likeボタン(off)0
詳細設定を開く/閉じる
アカウント プロフィール画像

パフォーマンス重視のRust開発者。WebAssemblyにも挑戦中。

記事の執筆者にステッカーを贈る

有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

>>さらに詳しくステッカーを贈る
ステッカーを贈る コンセプト画像

Feedbacks

Feedbacks コンセプト画像

    ログインするとコメントを投稿できます。

    ログインする

    関連記事

    • レイアウトおよび部分テンプレートに関するまとめ (Rails4)
      レイアウトおよび部分テンプレートはどちらもテンプレート (*.html.erb) に共通の要素をまとめておき、任意のテンプレートから利用できるようにしておくための仕組みです。フッターやヘッダーといった大枠はレイアウト、小さなパーツは部分テンプレートというイメージで使い分けましょう。 レイアウトの使用方法 クラス毎に指定する方法と、アクション毎に指定する方法があります。 app/views/layo...
      taro三世taro三世10/21/2016に更新
      いいねアイコン画像0
    • Ruby コードスニペット (正規表現)
      sample.rb str = "001: This is a string." var1,var2 = 2,3 # 'EOS'とすると#{}による変数展開がなされない (%03dは展開される) doc = (<<"EOS" % var1) # 括弧は省略可。要は<<"EOS"の次の行からEOSまで。(参: <<-"EOS"とすると前に空白...
      だいふくうさぎだいふくうさぎ5/13/2018に更新
      いいねアイコン画像0
    • OAuthを用いずにTwitterに自動投稿する (回数制限あり, Selenium with Ruby)
      Seleniumを用いて、OAuthを用いずにTwitterに自動投稿するRubyスクリプトを記述してみます。連続で複数回実行すると、ボット判定としてキャプチャ認証が発生します。その認証までは通過できませんので悪しからず。また、Twitterの仕様変更次第ではDOMの構造が変化するため、下記サンプルは機能しなくなる恐れが有ります。 twitter_post.rb #!/usr/bin/ruby r...
    • Ruby における日本語のエンコーディング
      日本語を含めて多言語対応する際には、Asciiコード以外の文字コードセットが必要になります。日本語が主となる場合、よく使われる文字セットにはUnicode, Shift_JIS, EUC-JPがあります。このうち Unicode だけは特殊であり、世界中のあらゆる文字を収録しようとしていることから 1 文字を表現するために必要なバイト数が大きくなってしまっています。そのため Unicode のうち...
      だいふくうさぎだいふくうさぎ4/21/2017に更新
      いいねアイコン画像0
    • Rails3ビューテンプレートの基本的な使用方法 (Ruby)
      Railsでは、ERB (eRuby (テキストファイルにRubyスクリプトを埋込む書式の仕様) をRubyで実装したもの) を用いてHTML内にRubyスクリプトを埋込むことができます。 <% %> で囲むと出力されません (if-elseなど制御構文を記述します) <%= %> で囲むとエスケープ出力されます <%== %> で囲むとエスケープされずに...
      ほんわかパンダほんわかパンダ10/21/2016に更新
      いいねアイコン画像0