Railsのflashとflash.nowを使い分ける。リダイレクトとrenderで考える

Railsのflashとflash.nowを使い分ける。リダイレクトとrenderで考えるの説明画像

操作結果のメッセージを、ちゃんと出したい

Railsでアプリを作っていると、ユーザーにメッセージを出したい場面がよくあります。

  • 登録が完了しました
  • 更新しました
  • 削除しました
  • 入力内容を確認してください
  • ログインしてください

こういう操作結果の表示には、Railsの flash が便利です。

ただ、最初に少し迷いやすいのが、flashflash.now の違いです。

この記事では、redirect_torender の違いから、flashflash.now の使い分けを整理します。

Railsのflashは、次のリクエストまで値を渡すもの

Rails Guides では、flash は controller action 間で一時的なデータを渡す仕組みとして説明されています。

Action Controller Overview - Ruby on Rails Guides

よく使うのは、リダイレクト後にメッセージを表示するケースです。

class UsersController < ApplicationController
  def create
    @user = User.new(user_params)

    if @user.save
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to @user
    else
      render :new, status: :unprocessable_entity
    end
  end
end

flash[:notice] に入れたメッセージは、redirect_to した次のリクエストで使えます。

登録完了後に詳細画面へ遷移し、そこで「ユーザー登録が完了しました」と表示するような使い方です。

レイアウトに表示処理を書いておく

flash の表示は、各ページに毎回書くより、レイアウトにまとめると楽です。

<% flash.each do |type, message| %>
  <div class="flash flash-<%= type %>">
    <%= message %>
  </div>
<% end %>

app/views/layouts/application.html.erb などに置いておけば、どのページでも共通で表示できます。

CSSも noticealert で分けておくと、成功と失敗が見分けやすくなります。

.flash-notice {
  color: #0f5132;
  background: #d1e7dd;
}

.flash-alert {
  color: #842029;
  background: #f8d7da;
}

flash.now は同じリクエストで表示したいときに使う

迷いやすいのが、保存に失敗して render :new する場合です。

render は新しいリクエストではありません。

同じリクエスト内でテンプレートを表示します。

この場合は flash.now を使います。

class UsersController < ApplicationController
  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to @user, notice: "ユーザー登録が完了しました"
    else
      flash.now[:alert] = "入力内容を確認してください"
      render :new, status: :unprocessable_entity
    end
  end
end

flash.now は、そのリクエスト内だけで使うメッセージです。

render で同じ画面を表示する場合に向いています。

redirect_to なら flash、render なら flash.now

まずは、この整理で十分です。

redirect_to する場合:
  flash または redirect_to の notice / alert を使う

render する場合:
  flash.now を使う

リダイレクトなら次のリクエストに渡す必要があります。

renderなら同じリクエストで表示したいだけです。

ここを混ぜると、メッセージが次の画面に残ったり、逆に表示されなかったりします。

よくあるミス

renderなのに flash を使う

flash[:alert] = "入力内容を確認してください"
render :new

この書き方でも、その場で表示されることがあります。

ただ、次のリクエストまでメッセージが残ってしまい、別ページで同じ alert が出ることがあります。

render のときは flash.now を使うほうが意図が明確です。

redirectなのに flash.now を使う

flash.now[:notice] = "更新しました"
redirect_to @user

これは、リダイレクト先ではメッセージが表示されません。

flash.now は同じリクエスト内だけなので、redirect で次のリクエストへ行くと消えます。

何でもflashに入れすぎる

flash は便利ですが、何でも入れるものではありません。

基本は一時的なメッセージに使うのがよいです。

  • 成功通知
  • エラー通知
  • 注意メッセージ
  • ログイン要求

長いデータや複雑な状態管理は、別の方法を考えたほうがよいです。

実務での使い分け例

自分なら、次のように使います。

def update
  if @user.update(user_params)
    redirect_to @user, notice: "プロフィールを更新しました"
  else
    flash.now[:alert] = "入力内容を確認してください"
    render :edit, status: :unprocessable_entity
  end
end

成功時は詳細画面へリダイレクトするので notice

失敗時は編集画面をそのまま表示するので flash.now[:alert]

この形にしておくと、読み手にも意図が伝わりやすいです。

Railsのenumを使いこなす のようなRails記事と同じく、Railsの便利機能は「いつ使うか」を整理するとかなり扱いやすくなります。

まとめ

flashflash.now の違いは、リクエストをまたぐかどうかで考えると分かりやすいです。

  • flash は次のリクエストまで残る
  • flash.now は今のリクエストだけで使う
  • redirect_to なら flash
  • render なら flash.now
  • 表示処理はレイアウトにまとめると楽

最初は少し紛らわしいですが、redirect_torender の違いに合わせて考えれば、かなりすっきりします。

操作結果のメッセージは小さな部分ですが、ユーザーにとっては大事です。

Railsの flash をうまく使って、分かりやすい画面にしていきたいですね。

この記事をシェア