10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Turbo Stream の flash メッセージを layout で共通化する

Last updated at Posted at 2023-09-09

結論

views/layouts/application.turbo_stream.erbviews/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.erbturbo/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

app/views/application/_turbo_stream_flash.erb
<% 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 されるレイアウト

app/views/layouts/application.turbo_stream.erb
<%= render 'turbo_stream_flash' %>
<%= yield %>

turbo_stream で、かつ turbo_frame_request のときに render されるレイアウト

app/views/layouts/turbo_rails/frame.turbo_stream.erb
<%= 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 に関する情報共有の場で、ゆるくおしゃべりをしたり、モブプロで実際の動きを試してみたりしています。興味のあるかたは是非遊びに来てください。

10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?