##はじめに
投稿機能やユーザー登録、ログインなど様々な場面で、うまく登録できなかった際にエラーメッセージの出力はあったほうが断然いいですよね。
私が開発中のオリジナルアプリで、少しアプリの中が複雑化していたこともあり、なかなかきれいにエラー文を出力できるまで時間がかかってしまいました。エラーメッセージやその周辺知識をこれから少しずつ発信できたらと考えています。
今回は、超基礎編、そもそもエラーメッセージをどうやって出力させるのか説明していきます。
よろしくお願いします。
##バリデーション
まずはバリデーションをモデルに書いてあげます。
バリデーションは、データベースに値を保存する際に、条件を満たしているかをチェックして、満たしていなかったら弾いてくれる、フィルター的役割をしてくれているものですね。
弾いた時に、なぜ登録できなかったのか、エラーメッセージを出力して知らせてあげることが今回の目標です。
例として、商品投稿機能のバリデーションを簡単に書いてみます。
class Item < ApplicationRecord
validates :name, presence: true
validates :description, presence: true
end
presenceを使って各カラムに空白だと弾けよ!というバリデーションを記述しました。
ちなみに正規表現などでもバリデーションを書くこともできます。任意の文字列だけを許可する、もしくは弾くといったような処理が可能になりますのでかなり便利です。
##エラーメッセージの表示
エラーメッセージを表示させる時には、フォームで情報を送信する時だと思います。
なのでビューではform_withメソッドを使ってフォームを実装していると仮定します。
<%= form_with(model: @item, local: true) do |f| %>
<%# 省略 %>
<% end %>
↑ビューではこのような記述でフォームを実装しているとします。
model: @item
という記述でitemモデルへ渡しているのですが、
createアクションで必ず@itemを定義してなければなりません。
def create
@item = Item.new(item_params)
if @item.save
redirect_to root_path
else
render :new
end
end
renderを使ってnewアクションをルーティングを介さずに実行させることで、もしバリデーションで弾かれた時に、書きかけのフォームをそのままに、エラーメッセージと共に再度newアクションのページが表示されます。
最後にビューのform_withの直下にこの記述をすれば完了です。
<%= form_with(model: @item, local: true) do |f| %>
<% if @item.errors.any? %>
<div class="error-alert">
<ul>
<% @item.errors.full_messages.each do |message| %>
<li class='error-message'><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%# 省略 %>
<% end %>
##汎用的に使用できるようにする
これでエラーメッセージは出力できるようになったかとは思いますが、あまり実用的ではありません。
なぜなら、ユーザー管理機能や他の機能にも同じようにエラーメッセージを出力させたい場合、何度もエラーメッセージの記述を書かなければなりません。
なのでいろんな場面で一つの文で汎用的に使えるようにしたいと思います。
問題はこの文ですね↓
<% if @item.errors.any? %>
<div class="error-alert">
<ul>
<% @item.errors.full_messages.each do |message| %>
<li class='error-message'><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
この文を切り出します。
viewフォルダの中に「shared」というフォルダを作成します。
その中に「_error_messages.html.erb」というファイルを作成します。
app/view/shared/_error_messages.html.erb
という構造になっていればOKです。
そのファイルにまるまる先ほどの記述を放り込んで、@itemの記述を下記のように書き換えます。
<% if model.errors.any? %>
<div class="error-alert">
<ul>
<% model.errors.full_messages.each do |message| %>
<li class='error-message'><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
そして、元々この記述があったform_withの直下に下記のように記述します。
<%= form_with(model: @item, local: true) do |f| %>
<%= render 'shared/error_messages', model: f.object %>
<%# 省略 %>
<% end %>
これでいろんな場面でform_withの直下にこの2行目の記述を書いてあげることでエラーメッセージを出力することができます。
記述量が大幅に削減できますし、コードがすっきりしましたね。
##最後に
今回はエラーメッセージを出力させることだけをやりましたが、他にもエラーメッセージに関わる周辺的な知識もやっていこうと思っています。
ここでの説明は私なりの解釈や理解に基づいていますので、ご指摘あれば突っ込んでいただけると幸いです。