Turbo Framesを使うと、ページの一部分だけを簡単に更新できます。
リンクやフォームをクリックすると、ページ全体ではなく、指定したフレーム内だけが更新されます。
RailsアプリケーションでTurbo Framesを使った部分更新の方法を詳しく解説します。
Turbo Framesとは?
Turbo Framesは、ページの一部分を独立したコンテキストとして扱い、その部分だけを更新できる仕組みです。
ページ内の特定の領域をturbo_frame_tag
で囲むことで、その領域内のリンクやフォームの送信結果が自動的にフレーム内だけで更新されます。
Turbo Framesの基本的な使い方
Railsでは、turbo_frame_tag
ヘルパーを使ってフレームを作成します。
各フレームには一意のIDが必要で、通常はモデルのインスタンスを渡して自動的に生成します。
<body>
<div id="navigation">ページ全体のナビゲーション</div>
<%= turbo_frame_tag @message do %>
<h1><%= @message.title %></h1>
<p><%= @message.content %></p>
<%= link_to "編集する", edit_message_path(@message) %>
<% end %>
<%= turbo_frame_tag dom_id(@message, :comments) do %>
<%= render @message.comments %>
<%= form_with model: [@message, Comment.new] do |form| %>
<%= form.text_area :content %>
<%= form.submit "コメントする" %>
<% end %>
<% end %>
</body>
この例では、メッセージ表示用のフレームとコメント表示用のフレームの2つがあります。それぞれのフレーム内のリンクやフォームは、そのフレーム内だけを更新します。
フレーム内でのページ更新の仕組み
例えば、メッセージ編集リンクをクリックすると、Railsはedit
アクションのレスポンスから同じIDを持つフレームを探し、その内容だけを置き換えます。
<!-- messages/edit.html.erb -->
<body>
<h1>メッセージ編集</h1>
<%= turbo_frame_tag @message do %>
<%= form_with model: @message do |form| %>
<%= form.text_field :title %>
<%= form.text_area :content %>
<%= form.submit "更新する" %>
<% end %>
<% end %>
</body>
このように、フレーム外の<h1>
は置き換えられず、フレーム内のフォームだけが置き換わります。
フレームの遅延読み込み(Lazy Loading)
フレームはページ読み込み時にすぐに読み込まなくても構いません。src
属性を指定すると、フレームが表示された時点で自動的に内容を読み込みます。
<%= turbo_frame_tag "notifications", src: notifications_path, loading: "lazy" do %>
<%= image_tag "spinner.gif" %>
<% end %>
この例では、通知一覧が画面に表示されるまで読み込みを遅延させ、表示時にnotifications_path
から内容を取得します。
フレームのキャッシュ活用
Turbo Framesを使うことで、ページのキャッシュ効率を高めることができます。
ユーザーごとに異なる部分をフレーム化することで、共通部分を効率よくキャッシュできます。
例えば、ユーザー固有の情報をフレーム化し、ページの大部分を共通キャッシュにすることが可能です。
フレーム外へのナビゲーション(target指定)
デフォルトでは、フレーム内のリンクやフォームはそのフレーム内だけを更新しますが、target
属性を指定することで、ページ全体や別のフレームを更新できます。
<%= turbo_frame_tag "sidebar", src: sidebar_path, target: "_top" %>
また、個別のリンクやフォームでdata-turbo-frame
属性を使って制御できます。
<%= turbo_frame_tag @message do %>
<%= link_to "編集する", edit_message_path(@message) %>
<%= link_to "権限変更", permissions_message_path(@message), data: { turbo_frame: "_top" } %>
<% end %>
フレームナビゲーションをページ訪問に昇格する(data-turbo-action)
フレーム内のナビゲーションをブラウザ履歴に残したい場合、data-turbo-action
属性を使います。
<%= turbo_frame_tag "articles", data: { turbo_action: "advance" } do %>
<%= link_to "次のページ", articles_path(page: 2), rel: "next" %>
<% end %>
これにより、フレーム内のナビゲーションがブラウザ履歴に反映されます。
フレームからの脱出(Breaking out)
フレーム内のリクエストがログインページなど、フレーム外のページにリダイレクトされる場合、フレームから脱出してページ全体を更新する必要があります。
Railsでは、以下のヘルパーを使って実現できます。
<!-- sessions/new.html.erb -->
<%= turbo_page_requires_reload %>
これにより、フレーム内からのリクエストでもページ全体がリロードされます。
CSRF対策(Rails標準対応)
TurboはRails標準のCSRFトークンを自動的にリクエストヘッダーに追加します。
特別な設定は不要です。
<!-- layouts/application.html.erb -->
<%= csrf_meta_tags %>
フレームのカスタムレンダリング(高度な使い方)
フレームのレンダリングをカスタマイズしたい場合、JavaScriptイベントを使って制御できます。
document.addEventListener("turbo:before-frame-render", (event) => {
event.detail.render = (currentElement, newElement) => {
// morphdomなどを使ったカスタムレンダリング
}
})
フレームレンダリングの一時停止(アニメーション対応)
レンダリング前にアニメーションなどを挟みたい場合、レンダリングを一時停止できます。
document.addEventListener("turbo:before-frame-render", async (event) => {
event.preventDefault()
await animateOut()
event.detail.resume()
})
まとめ
Turbo Framesを使うことで、Railsアプリケーションのページ更新を部分的に行い、UXを向上させることができます。
フレームを適切に活用し、モダンで高速なWebアプリケーションを構築しましょう。
以上が、Rails × HotwireのTurbo Frames入門記事のまとめです。