Turbo Streamsを使うと、ページの一部分をリアルタイムに更新したり、ユーザーの操作に応じてDOMを部分的に変更したりできます。
RailsアプリケーションでTurbo Streamsを使ったリアルタイム更新の方法を詳しく解説します。
Turbo Streamsとは?
Turbo Streamsは、HTMLの断片を<turbo-stream>
要素でラップしてブラウザに送信し、ページの一部分を動的に更新する仕組みです。
これにより、ページ全体をリロードせずに、特定の要素を追加・削除・置換することが可能になります。
Turbo Streamsは、HTTPレスポンスとして同期的に送信することも、WebSocketやServer-Sent Events(SSE)を使って非同期的に送信することもできます。
Turbo Streamsの基本構造とアクション
Turbo Streamsのメッセージは、以下のようなHTMLの断片です。
<turbo-stream action="append" target="messages">
<template>
<div id="message_1">新しいメッセージが追加されます。</div>
</template>
</turbo-stream>
各<turbo-stream>
要素は、以下の属性を持ちます。
action
: DOMに対して行う操作(append, prepend, replace, update, remove, before, after, morph, refresh)target
: 操作対象の要素のDOM IDtargets
: CSSセレクタを使って複数の要素を対象にする場合に使用
Turbo Streamsの主なアクション一覧
Turbo Streamsには以下の9つのアクションがあります。
アクション | 説明 |
---|---|
append | 対象要素の末尾に追加 |
prepend | 対象要素の先頭に追加 |
replace | 対象要素を完全に置換 |
update | 対象要素の中身を置換(要素自体は残る) |
remove | 対象要素を削除 |
before | 対象要素の直前に挿入 |
after | 対象要素の直後に挿入 |
morph | 対象要素をmorphdomで差分更新 |
refresh | Turbo Frameを再読み込み |
RailsでのTurbo Streamsの使い方(HTTPレスポンス)
Railsでは、コントローラーでTurbo Streamsを簡単に返せます。
# messages_controller.rb
def destroy
@message = Message.find(params[:id])
@message.destroy
respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.remove(@message) }
format.html { redirect_to messages_url }
end
end
フォーム送信時にTurbo Streamsを返す場合も同様です。
def create
@message = Message.create!(message_params)
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.append(:messages, partial: "messages/message", locals: { message: @message })
end
format.html { redirect_to messages_url }
end
end
サーバーサイドテンプレートの再利用
Turbo Streamsの最大の利点は、既存のサーバーサイドテンプレートをそのまま再利用できることです。
<!-- app/views/messages/_message.html.erb -->
<div id="<%= dom_id message %>">
<%= message.content %>
</div>
このテンプレートは、初回ページロード時にも、後から追加されるメッセージにも共通して使えます。
WebSocketやSSEを使ったリアルタイム更新
Turbo StreamsはWebSocketやSSEを使ってリアルタイムに更新を送信できます。
<!-- WebSocketを使った例 -->
<turbo-stream-source src="ws://example.com/cable"></turbo-stream-source>
<!-- SSEを使った例 -->
<turbo-stream-source src="/stream/messages"></turbo-stream-source>
RailsではActionCableを使って簡単に実装できます。
# message.rb (モデル側でブロードキャスト)
class Message < ApplicationRecord
after_create_commit { broadcast_append_to "messages" }
end
複数要素への一括操作(targets属性)
複数の要素を一括で操作する場合、targets
属性を使います。
<turbo-stream action="remove" targets=".old_messages"></turbo-stream>
カスタムアクションの追加
デフォルトの9つのアクション以外に独自のアクションを追加できます。
// JavaScriptでカスタムアクションを追加
import { StreamActions } from "@hotwired/turbo"
StreamActions.alert = function() {
alert(this.getAttribute("message"))
}
<turbo-stream action="alert" message="Hello, Turbo!"></turbo-stream>
JavaScriptの実行について(Stimulusとの連携)
Turbo Streamsは意図的にJavaScriptの直接実行を制限しています。
追加の動作を実行したい場合は、Stimulusコントローラーを使って実装します。
プログレッシブエンハンスメントの推奨
Turbo Streamsを使う前に、まずは通常のHTTPリクエストで動作するように設計しましょう。
その後、Turbo Streamsを追加してUXを向上させることで、堅牢で柔軟なアプリケーションになります。
まとめ
Turbo Streamsを使うことで、Railsアプリケーションにリアルタイム更新や部分的なDOM操作を簡単に導入できます。
既存のサーバーサイドテンプレートを再利用し、シンプルで保守性の高いコードを実現しましょう。