はじめに
flashメッセージとは、アクション実行後に簡単なメッセージを表示させるRailsの機能です。
なお、deviseの機能(ユーザー作成やログイン等)を使用した場合とそうでない場合で実装方法が違いますが、今回はdeviseを使用していない場合のflashメッセージの表示方法について説明していきます。
また前提として、今回はview部分をhaml記法にて記述します。
やりたいこと
Sendボタン押下にてメッセージを投稿した際に、flashメッセージが画面上部に表示されるよう実装します。今回はメッセージの投稿成功時と失敗時でメッセージが変わるようにします。
・投稿に成功した場合
水色の「メッセージが送信されました」部分がflashメッセージです。
・投稿に失敗した場合
オレンジ色の「メッセージを入力して下さい」部分がflashメッセージです。
「flash」を使用してflashメッセージを表示させてみる
大まかな流れは以下のとおりです。
- controllerを編集する
- viewを編集する
- CSSを追加する
1. controllerを編集する
flashメッセージ使用するためには、「FlashHash」というオブジェクトを使用します。
こちら、名前の通りハッシュオブジェクトです。
後述しますが、処理が成功した場合には[:notice]キーを、失敗した場合には[:alert]キーを使用します。
「Flash」や「FlashHash」についての詳細はこちらに書いてありますので、「Flash」でサイト内検索してみて下さい。
参考:Ruby on Rails ガイド
さて、本題に入っていきます。
結論から言うと、完成形の例はこんな感じです。
これから一つ一つ見ていきます。
1 def create
2 @message = @group.messages.new(message_params)
3 if @message.save
4 redirect_to group_messages_path(@group), notice: 'メッセージが送信されました'
5 else
6 flash.now[:alert] = 'メッセージを入力してください。'
7 render :index
8 end
9 end
投稿に成功した場合
例でいうと、3〜4行目が投稿に成功した場合の処理になります。
ただ、以下のほうがわかりやすいかと思うので、例とは少し違う書き方で説明します。
3 if @message.save
4 # 投稿に成功した場合
5 flash[:notice] = 'メッセージが送信されました' #ここが例と違う
6 redirect_to group_messages_path(@group) #ここが例と違う
5行目でflashオブジェクトのキーである[:notice]に表示したいメッセージをvalueとして追加しています。
6行目ではメッセージ登録後、リダイレクトをしてindex.htmlに遷移しています。
結果は同じですが、上記の処理は一行で記述できるので、完成形の例では以下のようにしています。こっちのほうがスッキリです。
4 if @message.save
5 redirect_to group_messages_path(@group), notice: 'メッセージが送信されました'
投稿に失敗した場合
5〜7行目が投稿に失敗した場合の処理になります。
5 else
6 flash.now[:alert] = 'メッセージを入力してください。'
7 render :index
6行目でflashオブジェクトのキーである[:alert]に表示したいメッセージをvalueとして追加しています。
成功時とは違い、flash.nowを使用しています。(※)
7行目ではメッセージ登録後、renderをしてindex.htmlに遷移しています。
※flashとflash.nowの使い分けについては後述
2. viewを編集する
controllerが完成したので、application.htmlを編集して画面に表示します。
まず最初に、追加する箇所はこんな感じ。
~~~~~~~~~~~~~~~~~~略~~~~~~~~~~~~~~~~~~
1 %body
2 #----------ここから----------
3 .notifications
4 - flash.each do |key, value|
5 = content_tag(:div, value, class: key)
6 #--------ここまでを追加--------
7 = yield
3~5行目のflashメッセージ部分は、HTMLに変換されると以下のような形になります。
<div class="notifications">
<div class="notice">メッセージが送信されました</div>
</div>
application.htmlはどのファイルを読み込む場合でも読み込まれる共通のviewです。
「= yeild」にて他のviewファイル(index.htmlとか)を読み込む事によって、そのviewファイルの内容が画面に表示されます。
今回は画面の上部にflashメッセージを表示させたいので、「= yeild」の前(他のviewファイルを読み込む前)にflashメッセージを実装しています。
それでは、実装箇所を一つ一つ見ていきます。
解説
3行目でflashメッセージの親要素となるdivタグを定義します。
.notifications
4行目でflashオブジェクトを呼び出しています。
投稿成功の場合、この時点で、keyに"notice"、valueに"メッセージが送信されました"が入ります。
.notifications
- flash.each do |key, value|
5行目でcontent_tagを使用してflashメッセージを表示させるためのdivタグを作成します。前述の通り、keyに"notice"、valueに"メッセージが送信されました"が入っていますので、classが"notice"、表示させたい内容が"メッセージが送信されました"となります。
.notifications
- flash.each do |key, value|
= content_tag(:div, value, class: key)
ちなみに、content_tagはHTMLタグを生成するメソッドで、以下のように使います。
content_tag(作成するタグの種類△表示したい内容△class等のオプション)
※△は半角スペース
3. CSSを追加する
上記のviewの実装にて追加したクラスにCSSを追加します。
ここは自由にCSSをあててください。一応、以下は例です。
.notifications {
color: $white;
text-align: center;
.notice {
background-color: lightBlue;
}
.alert {
background-color: alert_orange;
}
}
以上で、flashメッセージを表示させることが出きます。
flashとflash.nowの使い分け方は?
結論から言うと、以下のように使い分けます。
** ・flash: リダイレクトする時
・flash.now: renderする時**
なぜか?
それを理解するためには、以下の2つを理解する必要があります。
- リダイレクトとrenderの挙動の違い
- flashの特徴
リダイレクトとrenderの挙動の違い
こちらについては、以下の記事がわかりやすかったです。
参考:[【Rails】renderとredirect_toの違いと使い分け]
(https://qiita.com/morikuma709/items/e9146465df2d8a094d78)
一部抜粋せていただくと、、、"今回は"以下のような流れで次の画面を描写します。
・render : controller(createアクション) → view(index.html)
・redirect_to : controller(createアクション) → URL → route → controller(indexアクション) → view(index.html)
リダイレクトの場合、createアクションの直後にrouteを経由して次のindexアクションが実行される事がわかります。
言い換えれば、createアクションとindexアクションは別のリクエストとなります。
一方renderでは、createアクションの直後にindex.htmlを表示しています。
こちらは同じリクエストとなっています。
これを踏まえてflashの特徴を見ていきます。
flashとflash.nowの特徴について
■flashの特徴
flashについて、Railsのドキュメントには以下の様に記載されています。
flashはセッションの中の特殊な部分であり、*リクエストごとにクリアされます。つまりflashは「直後のリクエスト」でのみ参照可能になる*という特徴を持ち、エラーメッセージをビューに渡したりするのに便利です。
■flash.nowの特徴
flash.nowについて、Railsのドキュメントには以下の様に記載されています。
デフォルトでは、flashに値を追加すると直後のリクエストでその値を利用できますが、次のリクエストを待たずに同じリクエスト内でこれらのflash値にアクセスしたい場合があります。たとえば、createアクションに失敗してリソースが保存されなかった場合に、newテンプレートを直接描画するとします。このとき新しいリクエストは行われませんが、この状態でもflashを使ってメッセージを表示したいこともあります。このような場合、flash.nowを使えば通常のflashと同じ要領でメッセージを表示できます。
つまり今回で言うと、、、
メッセージ投稿成功時はリダイレクトしており、直後のリクエスト後(indexアクション後)にflashメッセージが参照可能となっているため、flashを使用しています。
また、メッセージ投稿失敗時には、同じリクエスト内でflashメッセージを表示したいので、flash.nowを使用しています。
参考:[Ruby on Railsドキュメント]
(http://railsdoc.com/references/flash)
まとめ
備忘として、flashメッセージの実装方法について纏めました。
理解不足により、認識が間違っている点や不明点等あればご指摘下さい。