概要
前回の記事(第2章)の続きです。
Railsの基礎を使って、メッセージ投稿アプリを作ってみた 【第2章】(3.リファクタリング〜5.バリデーションの設定まで
今回の第3章では、バリデーションエラーが発生した際のエラーの処理を実装していきます。
開発環境
- Ruby 2.7.3
- Rails 6.1.6.1
- Postgresql
開発手順
- アプリの作成 (第1章)
- CRUD処理で簡単なメッセージ投稿アプリを実装 (第1章)
- リファクタリング (第2章)
- フラッシュの実装 (第2章)
- バリデーションの設定 (第2章)
- エラーの処理 (第3章)
- Bootstrapでスタイルをつける (第4章)
エラーの処理
前回の記事でバリデーションを設定したことにより、空文字投稿、文字数制限を超える投稿をしたらバリデーションエラーが発生するようになりました。
そのエラーをユーザーにわかりやすく伝わるようにエラーメッセージを表示する作業に入ります。
エラーメッセージの日本語化
まずはGemfileに rails-i18n を追加し、多言語に対応できるようにします。
# 略
gem 'bootsnap', '>= 1.4.4', require: false
gem 'rails-i18n', '~> 6.0.0'
group :development, :test do
# 略
bundle install
多言語に対応できるようになったので、次に日本語に設定します。
config/application.rb にconfig.i18n.default_locale = :ja
を追記。
# 略
class Application < Rails::Application
config.load_defaults 6.1
config.i18n.default_locale = :ja
# 略
次に日本語訳をダウンロード
今回は、直接 curl コマンドでアプリ内に入れてしまします。
curl -o config/locales/ja.yml -L https://raw.github.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml
これでエラーメッセージが日本語化されましたが、モデルのカラムは日本語化されていないので、config/locales/ja.yml
に追記が必要です。
(yml形式は、インデントが1マスでもずれるとエラーになるので注意しましょう。)
---
ja:
activerecord:
models:
post: メッセージ
attributes:
post:
title: タイトル
content: 内容
errors:
# 略
ついでに、上記でカラムの日本語を設定したことで、投稿、更新フォームのラベルとしても使用できるので、変更しておきます。
<%= form_with model: @post, local: true do |form| %>
<div>
<%= form.label :title %> <!-- タイトルを消去 -->
<%= form.text_field :title %>
</div>
<div>
<%= form.label :content %> <!-- 内容を消去 -->
<%= form.text_field :content %>
</div>
これで、エラーメッセージを日本語化できたので、コンソールで確認してみましょう。
Post.create!(title: "", content: "")
Post.create!(title: "テスト", content: "")
Post.create!(title: "", content: "テスト")
Post.create!(title: "1" * 51, content: "テスト")
Post.create!(title: "テスト", content: "1" * 501)
エラーメッセージが日本語で表示されればOKです。
バリデーションエラー時の処理を変更
現状バリデーションエラーが発生すると、エラー画面が表示されます。
エラー画面ではなく、エラーメッセージが表示されるように、まずはコントローラでエラー時の処理を変更する必要があります。
if 文 を使って投稿内容にエラーがなければ、通常通りデータベースに保存し、指定のページにリダイレクト。
エラーがあった場合は、フラッシュメッセージを設定し、投稿ページ、もしくは更新ページにレンダリングする形とします。
# 略
def create
@post = Post.new(post_params)
if @post.save
redirect_to post_path(post), notice: '投稿しました'
else
flash.now[:alert] = '投稿に失敗しました'
render :new
end
end
# 略
def update
if @post.update(post_params)
redirect_to root_path, notice: '更新しました'
else
flash.now[:alert] = '更新に失敗しました'
render :edit
end
end
# 略
create
アクション、update
アクションでは、@post = Post.create!
のように!
をつけて例外が発生するようにしていました。
(例外とは、エラー画面が表示されることを意味します)
それを、!
をつけないように変更。
次に保存に失敗した場合は、フラッシュメッセージを設定し、リダイレクトではなく、レンダリングするように実装。
理由としては、リダイレクトにすると、エラーが発生したときに入力した内容が消えます。
レンダリングにすることで、入力した内容が残ったまま投稿ページ、もしくは更新ページに移動することができます。
フラッシュメッセージの設定ではレンダリングとフラッシュを併用するので、flash.nowを使用。
flash.nowであれば、次のアクションが実行された時点で、メッセージが消えるからです。
ここでレンダリングするときに注意点があります。
バリデーションエラーが発生した場合、
エラー箇所のラベル、フィールドが自動的に改行されてしまう。
これはRailsの仕様で、エラー箇所にdivタグがつくfield_with_errorsクラスが作成されるからです。
この仕様を使って、エラー箇所のフィールドだけ色を変え、目立たせることなどが可能となります。
なので、divタグで改行されてしまったのを、修正し、エラー箇所のフィールドを赤色になるよう修正していきます。
/* 略 */
div.field_with_errors {
display: contents;
input {
border: 2px solid red;
}
}
今回、フィールドを赤色にする作業で、SCSS記法を用いているので、拡張子を CSSからSCSSに変更しています。
これで、改行の修正、エラー時のフィールド枠の色変更は完了です。
エラーメッセージの表示
現状、バリデーションエラーが発生したら、
- 投稿ページにレンダリングされ、フラッシュメッセージが表示される。
- エラー箇所のフィールドが赤色になる。
しかし肝心のエラーメッセージが表示されていないので、何がエラーの原因なのかわからない状態です。
なので、これからエラーメッセージをビューファイルに表示する作業に入ります。
まずコンソールで、エラー時の状況を確認してみます。
post = Post.new(title: "テスト", content: "1" * 51)
post.save
post.save
を実行したら、false
と返ってきます。
post.errors
post.errors.full_messages
save
メソッド実行後に、post.errors
を実行すると、
@errors=[#<ActiveModel::Error attribute=content, type=too_long, options={:count=>500}>]>
contentが長すぎる(500文字を超えている)と書いてあります。
post.errors.full_messages
を実行すると、
=> ["内容は500文字以内で入力してください"]
とエラー内容が表示されました。
これをビューファイルに表示させれば、エラーの原因が分かります。
エラーメッセージは、フォームの上に表示させる方がわかりやすいので、別でエラーメッセージのファイルを作成し、レンダリングする形とします。
【新規作成】
<% if @post.errors.any? %>
<div>
<ul>
<% @post.errors.full_messages.each do |msg| %>
<li><span style="color: red;"><%= msg %></span></li>
<% end %>
</ul>
</div>
<% end %>
_form.html.erb
の一番上に書き、レンダリング。
<%= render "layouts/error_messages" %>
<%= form_with model: @post, local: true do |form| %>
<div>
<!-- 略 -->
サーバーを起動し、空投稿、文字数制限を超える投稿をして試してみることをお勧めします。
エラーメッセージがフォームの上に赤色で表示されればOKです。
これでエラーの処理から表示まで完了です。
次回の第4章(最終章)では、Bootstrapを使用して見栄えを良くする作業に入ります。
お疲れ様でした!