概要
flashはFlashHashクラスのインスタンスで、エラーなどのメッセージを遷移後の画面に表示するときに使う。ハッシュの様に状態キーに対するメッセージを登録するが、リクエストごとにクリアされる(Railsガイド)。
たとえばエラーメッセージの表示に使う手順は以下のとおり。
- バリデーションや保存処理などの結果に応じて、flashをセット
- flash[状態キー] = "メッセージ"
 
- リダイレクト後の画面でflashを参照し、状態キーに応じたメッセージを表示
基本動作
前提
たとえば以下の例ではform_withで@userの名前(:name)を入力して、ユーザー名が英数6文字以内であることを要求している。
app/views/flash_test.html.erb
| 1 2 3 4 5 6 | <h1>flashテスト</h1> <%= form_with model: @user, url: flash_test_process_path, local: true do |f| %>   <%= f.text_field :name, placeholder: "英数で6文字以内" %>   <button>送信</button> <% end %> | 
モデルのバリデーションで、ユーザー名の長さと構成文字の検証を行う。
- ユーザー名は6文字以上
- ユーザー名に使える文字は英数字のみ
app/models/user.rb
| 1 2 3 | class User < ApplicationRecord   validates :name, length: { minimum: 6 }, format: { with: /\A\w+\z/i } end | 
flashへの登録
通常はバリデーションはデータベースへの書き込み時に行われるが、ここではvalid?でバリデーションを強制している。
検証の結果が適正であればflashに:successのキーで「適正な入力」、不適正であれば:dangerのキーで「不適正な入力」のメッセージを登録している。
その後、結果によらず最初のページを表示するアクションへリダイレクト(リダイレクト先のページは任意だが、ここでは最初のページにしている)。
app/controllers/pages_controller.rb
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class PagesController < ApplicationController   def flash_test     @user = User.new   end   def flash_test_process     user = User.new(params.require(:user).permit(:name))     if user.valid?       flash[:success] = "適正な入力"       redirect_to flash_test_path and return     else       flash[:danger] = "不適正な入力"       redirect_to flash_test_path and return     end   end | 
flashに対応した表示
リダイレクト/レンダリング後のビューに、flashの結果に応じた表示を行うコードを追加する。
app/views/flash_test.html.erb
| 1 2 3 4 5 6 7 8 9 10 | <h1>flashテスト</h1> <%= form_with model: @user, url: flash_test_process_path, local: true do |f| %>   <%= f.text_field :name, placeholder: "英数で6文字以内" %>   <button>送信</button> <% end %> <% flash.each do |type, message| %>   <p class="notice notice-<%= type %>"><%= message %></p> <% end %> | 
flashのキー・値のセットの分だけeachで取り出して表示するが、その際にキーに応じたクラスを設定している。
そのレンダリング結果を確認してみよう。
遷移前のページでの入力が適正だった場合は、コントローラーでflashに:successをキーとして「適正な入力」のメッセージ文字列が渡される。このとき、キーの内容(:success)を使ってクラス設定が行われる。
| 1 |   <p class="notice notice-success">適正な入力</p> | 
一方、入力が不適正だった場合にはコントローラーでflashに:dangerをキーとするメッセージが渡され、それがレンダリングされた結果は以下のとおり。
| 1 |   <p class="notice notice-danger">不適正な入力</p> | 
この結果、遷移前のページでのバリデーション結果に応じた表示が行われる。
スタイルの変化
動的なクラス設定に対するスタイル
先のコードで、入力の結果に応じてメッセージのクラスが動的に設定された。スタイルファイルでそれらのクラスに応じたスタイルを定義することで、結果に応じた変化をつけることができる。
以下のスタイルファイルは、flashの結果セットされたクラスに応じてメッセージの色に変化をつけている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // for flash_test .notice {   border: 2px solid;   text-align: center;   &-success {     background-color: #9df;     color: #00f;   }   &-danger {     background-color: #fcc;     color: #f00;   } } | 
処理の概要は以下のとおり。
- flashによる通知全般のスタイル設定
 →- .notice
- flashのキー(- :success/:danger)に応じてセットされたクラスによって色を変化させる
 →- &_success/&_danger
<実行結果>
以下はバリデーションエラーの場合で、適正な場合は「適正な入力」と表示される。

ダイアログ表示
flashの内容を遷移後のページの表示前にダイアログで表示する場合、application.html.erbのhead部分にJavaScriptを記述。
app/views/layouts/application.html.erb
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <!DOCTYPE html> <html>   <head>     <title>Testapp</title>     <%= csrf_meta_tags %>     <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>     <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>     <script>       <% if flash.present? %>         alert("<%= flash.to_hash.values.join('\n') %>");       <% end %>     </script>   </head>   <body>     <%= yield %>   </body> </html> | 
処理の概要は以下のとおり。
- headブロックでダイアログ表示のスクリプトを定義
- flashがセットされている場合にダイアログを表示
- ダイアログのメッセージに、flashのすべてのメッセージを改行で結合して表示
<実行結果>

:dangerのときだけダイアログを表示する場合は以下の様になる。
| 1 2 3 4 5 |     <script>       <% if flash.present? && flash.to_hash.has_key?('danger') %>         alert("<%= flash[:danger] %>");       <% end %>     </script> | 
has_key?を使うため、to_hashでflashをハッシュに変換している。ただし、to_hashでハッシュに変換するとキーがシンボルではなく文字列になる点に注意。
一定時間後に表示を消す
flashに応じて表示されたメッセージを一定時間後に消すには、JavaScriptを使う。application.html.erbに以下の様に書く。
app/views/layouts/application.html.erb
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <!DOCTYPE html> <html>   <head>     <title>Testapp</title>     <%= csrf_meta_tags %>     <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>     <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>     <%= javascript_include_tag 'https://code.jquery.com/jquery-3.5.0.min.js' %>     <script>       <% if flash.present? && flash.to_hash.has_key?('danger') %>         alert("<%= flash[:danger] %>");       <% end %>     </script>   </head>   <body>     <% flash.each do |type, message| %>       <p class="notice notice-<%= type %>"><%= message %></p>     <% end %>     <%= yield %>     <script>       window.setTimeout(() => {         $(".notice").slideUp();       }, 1500);     </script>   </body> </html> | 
処理の概要は以下のとおり。
- 必要に応じてJQueryを読み込む
- bodyの最初(最上部)にメッセージ表示エリアを定義
- 一定時間表示させた後にスライドアップで表示を消すスクリプトを定義
- $(".notice").slideUp()でメッセージをスライドアップ消去
- 1.5秒後に消去を実行するよう、window.setTimeoutにコールバックとして渡す
 
なお、:successと:dangerによって表示の色を変える設定をCSSに書いている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | .flash_test {   h1 {     font-size: 24px;     margin: 10px;   }   input {     margin: 10px;   }   .notice {     margin-bottom: 10px;     padding: 5px;     border: 2px solid;     text-align: center;     font-size: 20px;     &_success {       background-color: #9df;       color: #00f;     }     &_danger {       background-color: #fcc;       color: #f00;     }   } } | 
<実行結果>
以下、danger/successに応じた表示で、1.5秒後にこれらの表示がスライドアップされて消去される。

