0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Railsの基礎を使って、メッセージ投稿アプリを作ってみた 【第3章】(6.エラーの処理)

Posted at

概要

前回の記事(第2章)の続きです。
Railsの基礎を使って、メッセージ投稿アプリを作ってみた 【第2章】(3.リファクタリング〜5.バリデーションの設定まで

今回の第3章では、バリデーションエラーが発生した際のエラーの処理を実装していきます。

開発環境

  • Ruby 2.7.3
  • Rails 6.1.6.1
  • Postgresql

開発手順

  1. アプリの作成 (第1章)
  2. CRUD処理で簡単なメッセージ投稿アプリを実装 (第1章)
  3. リファクタリング (第2章)
  4. フラッシュの実装 (第2章)
  5. バリデーションの設定 (第2章)
  6. エラーの処理 (第3章)
  7. Bootstrapでスタイルをつける (第4章)

エラーの処理

前回の記事でバリデーションを設定したことにより、空文字投稿、文字数制限を超える投稿をしたらバリデーションエラーが発生するようになりました。
そのエラーをユーザーにわかりやすく伝わるようにエラーメッセージを表示する作業に入ります。

エラーメッセージの日本語化

まずはGemfileに rails-i18n を追加し、多言語に対応できるようにします。

Gemfile
# 略

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を追記。

config/application.rb
# 略
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マスでもずれるとエラーになるので注意しましょう。)

config/locales/ja.yml
---
ja:
  activerecord:
    models:
      post: メッセージ
    attributes:
      post:
        title: タイトル
        content: 内容
    errors:
# 略

ついでに、上記でカラムの日本語を設定したことで、投稿、更新フォームのラベルとしても使用できるので、変更しておきます。

app/views/posts/_form.html.erb
<%= 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 文 を使って投稿内容にエラーがなければ、通常通りデータベースに保存し、指定のページにリダイレクト。
エラーがあった場合は、フラッシュメッセージを設定し、投稿ページ、もしくは更新ページにレンダリングする形とします。

app/controllers/posts_controller.rb
# 略
  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タグで改行されてしまったのを、修正し、エラー箇所のフィールドを赤色になるよう修正していきます。

app/assets/stylesheets/application.scss
/* 略 */

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文字以内で入力してください"]

とエラー内容が表示されました。
これをビューファイルに表示させれば、エラーの原因が分かります。
エラーメッセージは、フォームの上に表示させる方がわかりやすいので、別でエラーメッセージのファイルを作成し、レンダリングする形とします。

【新規作成】

app/views/layouts/_error_messages.html.erb
<% 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の一番上に書き、レンダリング。

app/views/posts/_form.html.erb
<%= render "layouts/error_messages" %>
<%= form_with model: @post, local: true do |form| %>
  <div>
<!-- 略 -->

サーバーを起動し、空投稿、文字数制限を超える投稿をして試してみることをお勧めします。
エラーメッセージがフォームの上に赤色で表示されればOKです。

これでエラーの処理から表示まで完了です。
次回の第4章(最終章)では、Bootstrapを使用して見栄えを良くする作業に入ります。

お疲れ様でした!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?