100
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

Rails エラーメッセージの出し方 バリデーションエラー

はじめに

DBに値を保存する際(ユーザー登録やツイートの登録等)のバリデーションエラー文を表示するやり方について備忘録のために記載しておきます。
参考程度にどうぞ。

バリデーションとは?

バリデーションとはDBに値を保存する際に何か値が抜けていると保存できなくするものです。
簡単に言えばフィルターみたいなものですね。

例えばユーザー登録時にpasswordを入力してもらうとします。passwordが「111」とかだったらセキュリティーが甘くなりますね。
そこでバリデーションを記載してpasswordを8文字以上にしないと登録できないようにすれば、「111」と入力しても弾かれて保存できないようになります。
バリデーションの組み方は無数にあり、やり方を変えれば自分の思い通りに値を保存することができます。

例1)
モデルに下記のように記載すれば空では保存できません。

product.rb
class User < ApplicationRecord
  validates :title, presence: true
end

例2)
モデルに下記のように記載すれば漢字のみ保存できるようになります。

product.rb
class User < ApplicationRecord
  kanji = /\A[一-龥]+\z/
  validates :name, format: { with: kanji }
end

例3)
モデルに下記のように記載すれば"2019-10-04"のような形でのみ保存できるようになります。

product.rb
class User < ApplicationRecord
  year_month_day = /\A\d{4}-\d{2}-\d{2}\z/
  validates :birthday, presence: true, format: { with: year_month_day }
end

バリデーションエラーメッセージの出し方

①商品の保存を行うアクション(ここではcreate)に保存の成功/失敗の条件分岐を記載。
ここで気をつけて欲しいのは失敗時のviewの読み込みはrenderを使用しましょう。
理由は後で解説します。

products_controller.rb
  def create
    @product = Product.new(product_params)
    if @product.save
      redirect_to controller: :products, action: :index
    else
      render "new"
    end
  end

②エラーメッセージのview作成
htmlのif文をmodel.errors.any? にしておくことでどのモデルのバリデーションにも対応させることができます。

layouts/_error_messages.html.haml
-if model.errors.any? 
  .alert
    %ul
      -model.errors.full_messages.each do |message| 
        %li= message
layouts/error_messages.scss
  .alert {
    color:#262626; 
    background:#FFEBE8;
    text-align: center;
    border:2px solid #990000;
    padding:12px; font-weight:850;
  }

③エラーメッセージの表示
あとはエラーメッセージを表示させたいところに以下のコードを記載するだけです。

products/new.html.haml
 = render 'layouts/error_messages', model: f.object

完成です。
こんな感じになります。めちゃめちゃ簡単です。

スクリーンショット 2019-10-04 17.31.25.png

redirect_toとrenderの違い

先ほど、失敗時のviewの読み込みはrenderを使用すると記載しましたが、そこについて軽く触れます。
redirect_toとrenderはルーティングを通るか通らないかという違いがあります。
redirect_to…ルーティングを通り、新たにviewページを呼び出す。
render…ルーティングを通らず、viewページに飛ぶ。

正式にはもっと違いがありますが、とりあえずこの認識でOKです。

なので失敗時のviewの読み込み(以下の部分)をredirect_toにすると、
新しいビューページが呼ばれてしまうため、ページに書いたif文が反応しません。

products_controller.rb
  def create
       ~省略~
    else
      render "new"
    end
  end

おわりに

特定のgem(例えばdeviseとか)には初めから実装されていることがあります。
ぜひ調べてみてください:santa::santa:

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
100
Help us understand the problem. What are the problem?