概要
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秒後にこれらの表示がスライドアップされて消去される。