flash[:notice]とflash.nowの違い

こんにちは!kossyです!



さて、今回はRailsでフラッシュメッセージを表示したい時に用いる、
flash[:notice]とflash.nowの違いについてブログに残してみたいと思います。

環境
Rails5.1.6
Ruby2.5.1
MacOS
haml



flashとは
例えば、ユーザーがアプリケーションに初めてログインした場合や、メッセージの投稿に成功した場合等に、
1回限りのインスタントメッセージを表示する仕組みをflashと呼びます。
基本的なflashの使い方は、コントローラでflashメッセージをkeyとvalue形式で設定し、ビューからflashをハッシュのように呼び出します。
また、flashは基本的にリダイレクトと同時に使うものなので、redirect_toメソッドを一緒に使うことが多いです。





flash[:notice]の使い方

まずは、viewにフラッシュメッセージを表示するように記述します。

application.html.haml

省略

%body
  - flash.each do |key, value|
    = content_tag :div, value, class: key
  = yield

flashメッセージの部分を部分テンプレート化するのもいいでしょう。

_flash.html.haml

.notification
  - flash.each do |key, value|
    = content_tag :div, value, class: key
application.html.haml
%body
  = render 'layouts/header'
  = render 'layouts/flash'
    = yield

次に、controller側で処理を記述します。
今回は、Reviewモデルのインスタンスを削除するdestroyメソッドが呼ばれた時を想定しています。

reviews_controller.rb

  def destroy
    @review = Review.find(params[:id])
    @review.destroy!
      redirect_to root_path, notice: '投稿の削除に成功しました!'
  end

削除に成功した場合、ルートパスにリダイレクトし、リダイレクト先でnoticeのメッセージ部分を表示するように記述しています。
redirect_toメソッドの場合、flash[:notice]とすることなく、引数にnoticeというキーを渡すだけで、
フラッシュメッセージを表示することができます。
参考URL: flashを使って簡易メッセージを表示する – Ruby on Rails 始めました






flash.nowの使い方
flash.nowを使うシチュエーションは、リダイレクトをしない場合です。
通常flashはリダイレクトを伴って利用しますが、リダイレクトを利用しなくても利用可能です。
その場合、flash[:notice]の代わりに、flash.nowを使います。
例として、レビューの投稿に失敗した時のエラーメッセージをflash.nowで表示してみます。

reviews_controller.rb

def create
  @review = Review.new(review_params)
    if @review.save!
      redirect_to root_path
    else
      flash.now[:alert] = '投稿に失敗しました'
      render :new
    end
end



違いはなんなのか
なぜリダイレクトをしない場合に異なる記述をするかというと、
flashメッセージの表示期間に関わっています。flashを使った場合のメッセージの表示期間は次のリクエストまでです。
現在のリクエストとリダイレクトのリクエスト分がメッセージの表示期間と合致するため、リダイレクト先でflashメッセージが表示されます。

対して、flash.nowの表示期間は現在のリクエストまでです。
リダイレクトを伴わない場合(上記のコードで言うと、render :newを使っているところ)、
flash[:notice]としてしまうと、メッセージは表示されるのですが、メッセージの表示期間は次のリクエストまでなので、
必要以上にメッセージが表示されてしまいます。





まとめ

redirecto_toを使う場合

redirect_to パス名, notice: "エラーメッセージ"

renderと共に使う場合

flash.now[:alert] = "エラーメッセージ"
render :アクション名

と覚えておけばいいでしょう。