🛤️

RailsのflashメッセージをTurbo Streamsで

2021/07/19に公開

TurboはRailsに関わらず使えるものですが、今回はRailsの機能に依存した話です。

以下は

  • @hotwired/turbo: 7.0.0-beta.8
  • turbo-rails: 0.5.12

を前提としています。

Railsと組み合わせてある程度Turboを使ってみて、HTTPレスポンスとしてTurbo Streamsを使うのは自分が想定していたよりもかなり使いどころがあるなと分かってきました。副作用があるリクエストの場合、レールに乗るならflashを利用してユーザに結果を伝えることになるのかなと思います。Turbo Streamsの場合に、自分がどのようにflashメッセージを使っているかをまとめてみることにしました。

ポイントとしては以下の2点です。

  • Trubo Streams用のlayoutを用意する
  • Turbo Streamsでのレスポンスを返す際には flash.now を使う

RJSを使っているなら大体同じようなことをしてるかと思います。

Turbo Streams用のlayoutを用意する

以下のようなlayoutを用意しておけば、Turbo Streamsのレスポンスを返す際に #alertsapp/views/application/_alert.html.erb のrender結果を追加してくれます。

app/views/layout/application.turbo_stream.erb
<% if flash[:notice] %>
  <%= turbo_stream.append("alerts") do %>
    <%= render "application/alert", type: :info, message: flash[:notice] %>
  <% end %>
<% end %>

<% if flash[:alert] %>
  <%= turbo_stream.append("alerts") do %>
    <%= render "application/alert", type: :warning, message: flash[:alert] %>
  <% end %>
<% end %>

<%= yield %>

アプリケーションに合わせて適宜調整してください。

Turbo Streamsでのレスポンスを返す際には flash.now を使う

Turbo Streamsでレスポンスを返す場合、リダイレクトをはさまないので flash.now を使う必要があります。Turbo Streamsを受けれてくれない場合にはリダイレクトしたいので、僕は request.format に応じて適切なものを使うためのメソッド ApplicationController に定義してしまっています(concernに切り出した方が良いかも)。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # ...
  def appropriate_flash
    case
    when request.format.turbo_stream?
      flash.now
    else
      flash
    end
  end
  # ...
end

単純化したコントローラでの利用例は以下のようになります。

app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def create
    comment = Comment.create!(create_params)    
    appropriate_flash[:notice] = "コメントを投稿しました"
    respond_to do |format|
      format.turbo_stream # app/views/comments/create.turbo_stream.erb
      format.any { redirect_to comments_path }
    end
  end  
  # ...
end

以上です。

Discussion