結論
views/layouts/application.turbo_stream.erb
と views/layouts/turbo_rails/frame.turbo_stream.erb
に書くのがよさそう。
解説
Rails では layouts/application.html.erb に flash メッセージの表示処理を書いておくのが一般的で、turbo_stream でも layouts/application.turbo_stream.erb を用いてメッセージの表示処理を共通化することができます。しかし、turbo_frame 内からリクエストされた場合は、この layout が適用されず、flash メッセージを出力するには別の工夫が必要でした。
これは turbo_frame リクエストのときは layout: false
となるようになっていたためですが、turbo-rails v1.4.0 で以下のように変更されました。
included do
- layout -> { false if turbo_frame_request? }
+ layout -> { "turbo_rails/frame" if turbo_frame_request? }
etag { :frame if turbo_frame_request? }
end
このとき、デフォルトの layout ファイルは以下のように適用されます。
- format.html => application.html.erb
- format.turbo_stream => application.turbo_stream.erb
- format.html + turbo_frame request => turbo_rails/frame.html.erb
- format.turbo_stream + turbo_frame request => turbo_rails/frame.turbo_stream.erb
つまり turbo-rails v1.4.0 以降では、application.turbo_stream.erb
と turbo/frame.turbo_stream.erb
を追加し、この2つのファイルに flash メッセージの出力処理 (turbo_stream.update など) を記載しておけばよい、ということになります。
どうしても turbo-rails v1.4.0 より前のバージョンを利用したい場合は、カスタムレイアウトを用意しておくとよさそうです。
サンプルコード
前提
flash メッセージを表示するには、id="flash_messages"
の要素にメッセージを含む要素を追加するものとします。また、この記事のサンプルコードは CSS を省きます。
<div id="flash_messages">
<p>処理成功のメッセージなど</p>
</div>
flash メッセージを表示するための partial view
<% if notice || alert %>
<%= turbo_stream.update 'flash_messages' do %>
<% if notice %>
<p><%= notice %></p>
<% end %>
<% if alert %>
<p><%= alert %></p>
<% end %>
<% end %>
<% end %>
turbo_stream のレイアウトファイル
turbo_stream で、かつ turbo_frame_request ではないときに render されるレイアウト
<%= render 'turbo_stream_flash' %>
<%= yield %>
turbo_stream で、かつ turbo_frame_request のときに render されるレイアウト
<%= render 'turbo_stream_flash' %>
<%= yield %>
まったく同じ内容のファイルなので application.turbo_stream.erb
のみにまとめたいところですが、カスタムレイアウトのメソッドを用意して turbo_stream の分岐をいれて〜と処理を足すより、これくらいのコード量であればファイルを2つ用意した方がよいと考えています。
コントローラ/アクションメソッドの例
def create
@some_model = SomeModel.new(some_model_params)
if @some_model.save
flash.now.notice = '登録しました。'
# turbo_stream でページ更新する
else
render :new, status: :unprocessable_entity
end
end
def update
if @some_model.update(some_model_params)
flash.now.notice = '更新しました。'
# turbo_stream でページ更新する
else
render :edit, status: :unprocessable_entity
end
end
参考
「猫でもわかるHotwire入門 Turbo編」に、turbo_stream における flash メッセージの表示や stimulus による toast 化など、すごく詳しい解説が載っています。とても参考になります。
告知
hotwire.love という hotwire の勉強会を毎月第2/第4木曜に開催しています。hotwire に関する情報共有の場で、ゆるくおしゃべりをしたり、モブプロで実際の動きを試してみたりしています。興味のあるかたは是非遊びに来てください。