【Rails】完全保存版!flashの使い方についてを徹底解説!

Rails

flashとは

ユーザーに対してページ遷移した時に簡単なメッセージを一時的に表示させる機能です。

flashの役割
リンクをコピーしました

例えばユーザー登録が完了した時とか、失敗した時にメッセージを表示させてあげるとユーザーにとって優しいですよね。
検証で保存されなかった時なども、どういう原因で保存が失敗したかなどメッセージで教えてあげるとより親切です。
そんな時に使うのがflashメッセージです。

flashメッセージ

上の例だと「名前を入力してください」がflashメッセージです。
常時表示されるわけではなく、一時的に表示されるメッセージとなります。

flashの基本的な書き方
リンクをコピーしました

flashはハッシュのような形式で記述します。

コントローラー
1
flash[:キー名] = "表示させたいメッセージ"

上のキー名は自分の好きな名前をつけることができます。

フラッシュメッセージを表示させたい箇所に下記のように記述します。

ビューファイル
1
<%= flash[:キー名] %>

具体的には下記のように記述します。

コントローラー
1
2
3
4
5
6
# 例
if article.save
  flash[:notice] = "登録が完了しました。"
  redirect_to root_path
else
  ~  ~
ビューファイル
1
<%= flash[:notice] %>

ビューファイルで上のコードを書いた箇所にflashメッセージが表示されます。

noticeが表示されている

noticeとalertオプション
リンクをコピーしました

キーには好きな名前をつけられますが、あらかじめnoticeとalertはオプションが用意されています。
この2つは下記のように使用が可能です。

ビューファイル
1
2
<%= notice %>
<%= alert %>

このようにflashを省略して書く事ができます。

「notice」は何かの通知に、「alert」は警告のメッセージという風に使い分けると良いでしょう。

flash用の部分テンプレートを作ろう
リンクをコピーしました

flashメッセージは複数のビューファイルで使うので、部分テンプレートにしておくと便利です。

layouts/_flash.html.erb
1
2
3
4
5
<% flash.each do |key, value| %>
    <p class="alert alert-<%= key %>">
      <%= value %>
    </p>
<% end %>

flashはhashのようなものなのでeachメソッドを使うことができます。
上のように書くと「flash[:キー名] = "メッセージ"」の部分の「キー名」を「key」で、「メッセージ」を「value」で取得できます。
この「key」と「value」という変数名は任意で決められます。

試しに下記のコードを実行してみます。

コントローラー
1
flash[:alert] = "名前を入力してください"

今回はキー名に「alert」を、メッセージに「名前を入力してください」と定義しました。
これを表示させるためにビューファイルに下記のように書いてみます。

ビューファイル
1
2
3
4
<% flash.each do |key, value| %>
  <p>キー名: <%= key %><p>
  <p>メッセージ: <%= value %><p>
<% end %>

するとこのようにちゃんとキー名とメッセージが表示されました。

flash.each

layout/_flash.html.erb
1
2
3
4
5
<% flash.each do |key, value| %>
    <p class="alert alert-<%= key %>">
      <%= value %>
    </p>
<% end %>

先ほどの上のコードはcontent_tagメソッドを使うと下記のように記述することもできます。

layout/_flash.html.erb
1
2
3
<% flash.each do |key, value| %>
  <%= content_tag(:p, value, class: "alert alert-#{key}") %>
<% end %>

content_tagメソッド
リンクをコピーしました

タグを簡潔に書くことができるメソッドです。
下記のように定義します。

ビューファイル
1
<%= content_tag(:タグ名, "表示する文字", class: "クラス名") %>

今回はキーをメッセージが表示されるスタイルのクラス名の部分で、バリューを実際に表示される文字として使っています。

呼び出したい部分には下記のように記述しましょう。

ビューファイル
1
<%= render partial: 'layouts/flash' %>

redirect_toの時の書き方
リンクをコピーしました

redirect_toでnoticeとalertを使う時は非常に簡潔に記述することができます。

コントローラー
1
2
3
4
5
# 例
if article.save
  redirect_to root_path, notice: "表示させたいメッセージ"
else
  ~  ~

他のキーの場合は下記のように記述します。

コントローラー
1
2
3
4
5
# 例
if article.save
  redirect_to path, flash: {キー名: "表字させたいメッセージ"}
else
  ~  ~

この場合は下記のように記述します。

コントローラー
1
2
3
4
5
# 例
if article.save
  redirect_to path, flash: {success: "登録が完了しました"}
else
  ~  ~

redirect_toは一度アクションが実行されてからビューが表示されます。
ですのでredirect_toの場合は下の図のような流れとなります。

redirect_toの場合

上の流れになるので、最初のアクションが実行された後の1回のみflashメッセージが表示されます。

renderの時の書き方
リンクをコピーしました

flashメッセージはアクションが動いた時に表示され、次のアクションが動くと消去される仕組みになっています。
renderメソッドを使うときはアクションを通さないでビューファイルをレンダリングするため、次のアクションが動いた後にflashメッセージが表示されてしまいます。

renderの場合は表示された後、最初のアクションが実行されます。
flashメッセージは2回目のアクションが実行された時に削除されるため、2回flashメッセージが表示されてしまいます。

コントローラー
1
2
3
4
5
6
7
# 例
if article.save
  redirect_to root_path, notice: "登録が完了しました"
else
  flash[:alert] = "名前を入力してください"
  render :new
end

上のコードは保存が失敗したらrenderメソッドにより同じビューがレンダリングされます。
renderメソッドを使っているので、アクションは実行されません。
そしてTOPをクリックするとtopページのindexアクションを通してルートパスが表示されるようになっています。

flashメッセージ

flashメッセージはアクションが実行された時、次のアクションが実行されるまで保存され表示されます。
そして次にアクションが実行される時に削除される仕組みになっています。
ですのでtopページのindexアクションがrender後の初めてのアクションの実行になります。

render

上の流れで動くのでこのようにルートパスのビューにもflashメッセージが残ってしまいました。
次にnewアクションが動くことによって表示が消えるのが確認できます。
これでは困るのでflash.nowを使用します。

flash.nowを使った場合は下の図のような流れとなります。

flash.now

コントローラー
1
2
3
4
5
6
7
# 例
if article.save
  redirect_to root_path, notice: "登録が完了しました"
else
  flash.now[:alert] = "名前を入力してください"
  render :new
end

flash.nowを使った時の挙動を確認してみます。

flash.now

このように次のアクションが動いてもメッセージが持ち越されなくなっているのが確認できますね!
次のアクションが動くまで表示されるので、renderでビューファイルが表示される限りずっとflashメッセージは表示され続けます。

flashとflash.nowの違い
リンクをコピーしました

上の例のようにflash次のアクションが動いた後のビューファイルにflashメッセージを表示する時に、
flash.now現在のアクションで表示するビューファイルのみ有効なflashメッセージを表示させたい時(renderで表示させたい時)に使用します。

flash.keepの使い方
リンクをコピーしました

前述した通りflashメッセージはアクションが動いた時に表示され、次のアクションが動くと消去されますが、flash.keepを使うと指定されたフラッシュを次のアクションに持ち越すことができます。

コントローラー
1
2
3
4
5
# 全てのflashメッセージが持ち越される
flash.keep

# 指定したキーのflashメッセージが持ち越される
flash.keep(:キー名)
コントローラー
1
2
3
4
5
6
7
8
9
10
11
# 例
before_action :flash_keep

# 中略

private

def flash_keep
  flash.now[:alert] = "名前を入力してください"
  flash.keep(:alert)
end

上のように定義するとアクションが2回実行された後もflashメッセージは残り続けます。

flash.keep

flash.discardの使い方
リンクをコピーしました

次に動くアクションまで有効なflashメッセージを、今のアクション内のみ有効なflashメッセージに変える方法があります。
それがflash.discardです。

コントローラー
1
2
3
4
5
# 全てのflashメッセージを破棄する
flash.discard

# 指定したキーのflashメッセージを破棄する
flash.discard(:キー名)

下記のように使います。

コントローラー
1
2
3
4
5
6
7
8
# 例
if article.save
  redirect_to root_path, notice: "登録が完了しました"
else
  flash[:alert] = "名前を入力してください"
  flash.discard(:alert)
  render :new
end

上のように記述すると現在のアクション内のみ有効なflashメッセージになるのでflash.nowを使った時と同じ挙動になります。

flash.now

flashをbootstrapで表示しよう
リンクをコピーしました

cssのフレームワークであるbootstrapを使うとflashメッセージをかっこよく表示させることができます。
その前にrailsでbootstrapが使えるよう準備をする必要があります。

railsにbootstarpを導入しよう
リンクをコピーしました

railsにbootstrapを導入するにはGemfileにgemを追加します。
下記のコードをGemfileに追記し、bundle installコマンドを実行しましょう。

Gemfile
1
2
gem 'jquery-rails'
gem 'bootstrap', '~> 4.1.1'

次にapp/assets/stylesheets/application.cssの拡張子をscssに変更し、下記の一文を追記します。

application.scss
1
@import "bootstrap";

bootstrapのjavascriptを対応させるために下記のコードをapp/assets/javascripts/application.jsに追記します。

application.js
1
2
3
//= require jquery3
//= require popper
//= require bootstrap-sprockets

これで準備は完了です。

flashメッセージにbootstarpのデザインを当ててみよう
リンクをコピーしました

では実際にbootstarpで定義されているスタイルを当ててみましょう。
bootstrapではflashメッセージ用に下記のようなスタイルが用意されています。

css
1
2
3
4
<タグ class="alert alert-色の指定">

# 
<p class="alert alert-primary">

このスタイルを当てると下記のようなデザインになります。

primary

上のコードのprimaryの部分が色を指定する箇所になります。
この部分をbootstrapで定義されているクラス名に変更することにより色を変えることができます。

上のprimary以外にも下記の色が定義されています。

secondary
リンクをコピーしました

css
1
<p class="alert alert-secondary">

secondary

success
リンクをコピーしました

css
1
<p class="alert alert-success">

success

danger
リンクをコピーしました

css
1
<p class="alert alert-danger">

danger

warning
リンクをコピーしました

css
1
<p class="alert alert-warning">

warning

info
リンクをコピーしました

css
1
<p class="alert alert-info">

info

light
リンクをコピーしました

css
1
<p class="alert alert-light">

light

dark
リンクをコピーしました

css
1
<p class="alert alert-dark">

dark

部分テンプレートに合わせる必要があるので、キー名に色の指定を設定しましょう。

コントローラー
1
2
3
4
5
6
# 例:緑色で表示させたい場合
if article.save
  flash[:success] = "登録が完了しました。"
  redirect_to root_path
else
  ~  ~

こうすれば下記の「key」の部分に色を指定する「success」が入るので、緑色のデザインが適用されます。

layout/_flash.html.erb
1
2
3
<% flash.each do |key, value| %>
  <%= content_tag(:p, value, class: key) %>
<% end %>

flashメッセージに閉じるボタンを付けよう
リンクをコピーしました

flashメッセージは次のアクションが動くまで消えません。
なのでflashメッセージが表示されているページで手動でflashメッセージを閉じることができる機能をつけてみましょう。

ビューファイル
1
2
3
<div class="alert alert-danger">
  <%= alert %><button type="button" class="close" data-dismiss="alert">&times;</button>
</div>

上のように記述するとbootstrapのjavascriptが実行され、×ボタンを押すとflashメッセージが削除されます。
今回「×」は特殊文字の「&times;」で指定しています。

button

このように自分でflashメッセージを削除することができるようになりました。
ただし、これはbootstrapを導入していないと使えないので、導入していない場合は自分でjavascriptを作成する必要があるので注意しましょう。

このようにflashメッセージはとても便利な機能です。
ただflashメッセージはrails側で保存されるのではなく、自分のPCのCookieにデータを保存して表示させています。
なのでCookieが無効になっているブラウザでは表示されないので気をつけましょう。

まとめ

・flashは簡単なメッセージを1回だけ表示させる事ができる便利な機能です。
・flashメッセージ用の部分テンプレートを作成しておくと便利です。
・同じリクエスト内でflashを使う時はflash.nowを使います。