【Rails】Flashメッセージの使い方とメッセージの拡張・応用

何かの処理を行った時に(例えば以下のような)

・ユーザー登録に成功しました
・ログインしました
・口コミの投稿が成功しました
・写真を投稿しました
・本人確認に失敗しました

flashメッセージを使うことでメッセージを表示することができます。今日はflashメッセージの使い方と拡張・応用をしてみたのでそれを備忘録しています。

私は「写真を投稿しました」の時だけ「SNSボタンを表示してシェアしてみませんか?」みたいなこともやりたかったので、それも実装しました。

まずは簡単なflashメッセージの使い方

使い方は簡単です。コントローラー側で処理を行いそれにたいして(成功とか失敗とかの)flashメッセージを作成します。ビュー側でflashメッセージを表示します。

◆コントローラー側

flash[:success] = '写真を投稿しました'
flash[:danger] = '写真の投稿に失敗しました'
flash[:notice] = 'お知らせ'
flash[:aiueo] = '文字列を入力'

こんな形です。flashメッセージはいわばハッシュなのでkeyとvalueを設定してあげる形です。

通常コントローラーからビューに変数を渡す時は変数の頭に@を付けるルールがあったと思いますが、flashメッセージには不要なようです。(railsドキュメント flashのリファレンス

◆ビュー側

以下のようにしてメッセージを表示できます。

<%= flash[:success] %>
<%= flash[:danger] %>
<%= flash[:notice] %>
<%= flash[:aiueo] %>

erbではhメソッドでHTMLエンコードも行うなら(例えば&は&amp;とか<は&lt;とか)

<%= h(flash[:success]) %>
<%= h(flash[:danger]) %>
<%= h(flash[:notice]) %>
<%= h(flash[:aiueo]) %>

こんな形になります。

もしflashメッセージにHTMLタグを使うなら以下のように使えばよいでしょう。

◆コントローラー側

<br>タグで改行してみます。

flash[:aiueo] = '明日は<br>晴れるかなぁ'

◆ビュー側

html_safeメソッドを使ってHTMLタグをタグとして出力してくれます。

<%= flash[:aiueo].html_safe %>

flashメッセージが消えないときは

先程のリファレンスを見ると、flash.nowというメソッドがあるのでそれを活用すれば良いと思います。これで今のアクションにだけ適用されます。

コントローラー側で以下のように記述。

flash.now[:abc] = 'あべし'

逆にflashメッセージの有効期限を保持するのであれば、キーと値を設定した後に以下のようにメソッドを呼び出します。

flash.keep(:abc)

flashメッセージを外部ファイルでパーシャルにすると楽

パーシャルはどのビューにも共通する部分をまとめたファイルです。アンダーバーで始まるファイル名にします。

例えば、views/layouts/_flash_messages.html.erbというファイルを作ってそこにflashメッセージの表示部分を任せます。このやり方はテックアカデミーの教材で学びました。

外部ファイルの中身を以下のようにしています。

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

これをビュー側でrenderメソッドを使って呼び出します。呼び出す時はディレクトリ/アンダーバーを消したファイル名(.html.erbも書かない)とします。

<%= render 'layouts/flash_messages' %>

flashメッセージのテクニック

もしcssでbootstrapによるデザインを使っているなら、flashメッセージのハッシュのkeyには:successや:infoや:dangerや:warningを使うことをおすすめします。(bootstrapじゃなくて自作のcssでも応用すれば良いと思います。)

bootstrapには以下の4つのcssのclassがありまして。

<div class="alert alert-success">成功時のメッセージカラーは緑</div>
<div class="alert alert-info">通知用のメッセージカラーは青</div>
<div class="alert alert-warning">警告用のメッセージカラーは黄色</div>
<div class="alert alert-danger">危険用のメッセージカラーは赤色</div>

それぞれ以下のようなイメージでメッセージ表示用の吹き出しが出ます。これを活用しているのです。

flashメッセージの表示部分のここ↓ですね。

<% flash.each do |message_type, message| %>
  <div class="alert alert-<%= message_type %>">

flashメッセージのハッシュのkeyはflashのeach doで、message_typeで取り出してるのでbootstrapのクラス名に合わせることで、自動的に吹き出しの色を指定してるだけなんですが。

そして以下の部分でコントローラー側で設定したメッセージを表示します。

      <%= message %>

成功したときにSNSボタンを表示させる

これは私自身が運営するWEBアプリで、そういう仕様にしたいと思いまして。

ユーザーによる投稿処理が成功したら、その画面でさらにSNS(FBやTwitter)にシェアをしてもらえたらな、という思いです。写真投稿に成功したときだけこのSNSボタンを表示させます。(SNSボタンを表示する方法に関しては前の記事に書いてあります。→【Rails】自作のSNSボタンを貼り付ける方法

特に難しいことはなくて。

コントローラー側では以下のように記述。

    if @photo.save  #ここで写真を保存
      flash[:photosuccess] = '写真を投稿しました!'
    else 
      flash[:danger] = '写真の投稿に失敗しました'
    end
    
    redirect_to @shop

ビュー側(shops/show.html.erb)では以下のように記述。renderでflash_messagesを呼び出してるだけです。

  <%= render 'layouts/flash_messages' %>

パーシャル(layouts/flash_messages.html.erb)では以下のように記述。

<% flash.each do |message_type, message| %>

  <% if flash[:photosuccess] %>
    <div class="alert alert-success">
      <%= message %>
      <p>是非SNSでも当サイトをシェアしてください。</p>
      <%= render 'layouts/snsbutton' %>
    </div>
  <% else %>
    <div class="alert alert-<%= message_type %>">
      <%= message %>
    </div>
  <% end %>
<% end %>

これは3行目でflash[:photosuccess]があれば、「是非SNSでも当サイトをシェアしてください。」を表示して、なおかつ次の行でrenderメソッドで外部ファイルの_snsbutton.html.erbを表示しています。(この_snsbutton.html.erbにはSNSボタンが記述されています)

ということで投稿をしてもらった時だけ以下のようなSNSへのシェアを促すflashメッセージを出すようにしました。