hotwire-coder について
Rails アプリケーションで Hotwire 機能を実装するための開発スキルです。Turbo Drive、Frames、Streams、リアルタイム配信、一般的な UI パターンを扱い、実装成果物の構成も示します。
主な機能
- 01Turbo Drive によるナビゲーション
- 02Turbo Frames による部分更新
- 03Turbo Streams と配信
- 04モーダルと無限スクロールのパターン
- 05デバッグとアンチパターンの指針
活用シーン
- 01ページの部分更新の追加
- 02リアルタイムコメント表示の構築
- 03モーダルまたは無限スクロール画面の実装
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ majesticlabs-dev/ majestic-marketplace --skill hotwire-coderインストール後、Claude Code で/hotwire-coderを入力して読み込まれたか確認します。
同梱ファイルreferences/lazy-loading.md
詳細
Hotwire コーダー
Hotwire の理念
Hotwire は JSON の代わりに HTML を通信で送信します。
- Turbo Drive - ページ全体を再読み込みせずに
<body>を置き換えて、ナビゲーションを高速化します - Turbo Frames - ページを、リクエストに応じて更新される独立したコンテキストに分割します
- Turbo Streams - サーバーからページの一部を更新します(HTTP または WebSocket)
Turbo Drive
選択的なオプトアウト
<%= link_to "Download PDF", report_path(format: :pdf), data: { turbo: false } %>
<%= form_with model: @legacy, data: { turbo: false } do |f| %>
フォームの送信
def create
@post = Post.new(post_params)
@post.save ? redirect_to(@post, notice: "Created!") : render(:new, status: :unprocessable_entity)
end
Turbo Frames
基本的なフレーム
<turbo-frame id="comments">
<%= render @post.comments %>
<%= link_to "Load More", post_comments_path(@post, page: 2) %>
</turbo-frame>
遅延読み込み
<turbo-frame id="notifications" src="<%= notifications_path %>" loading="lazy">
<p>Loading...</p>
</turbo-frame>
スケルトン UI のパターン、無限スクロール、Stimulus の読み込みコントローラーについては、references/lazy-loading.md を参照してください。
フレームから抜け出す
<%= link_to "View Post", post_path(@post), data: { turbo_frame: "_top" } %>
<%= link_to "Results", search_path, data: { turbo_frame: "results" } %>
インライン編集パターン
<turbo-frame id="<%= dom_id(post) %>">
<article>
<h2><%= post.title %></h2>
<%= link_to "Edit", edit_post_path(post) %>
</article>
</turbo-frame>
Turbo Streams
ストリームアクション
<%= turbo_stream.append "comments" do %><%= render @comment %><% end %>
<%= turbo_stream.replace dom_id(@post) do %><%= render @post %><% end %>
<%= turbo_stream.remove dom_id(@comment) %>
HTTP ストリームのレスポンス
def create
@comment = @post.comments.create(comment_params)
respond_to do |format|
format.turbo_stream # renders create.turbo_stream.erb
format.html { redirect_to @post }
end
end
リアルタイム配信
class Comment < ApplicationRecord
after_create_commit -> {
broadcast_append_to post, target: "comments", partial: "comments/comment"
}
after_update_commit -> { broadcast_replace_to post }
after_destroy_commit -> { broadcast_remove_to post }
end
<%= turbo_stream_from @post %>
<div id="comments"><%= render @post.comments %></div>
注記: LLM のストリーミングや、メッセージ配信の保証が必要な機能については、
anycable-coderスキルを参照してください。Action Cable は最大 1 回の配信を提供するため、再接続時にチャンクが失われることがあります。
Turbo 8 のモーフィング
<head>
<meta name="turbo-refresh-method" content="morph">
<meta name="turbo-refresh-scroll" content="preserve">
</head>
class Post < ApplicationRecord
after_update_commit -> { broadcast_refresh_to self }
end
よくあるパターン
モーダルパターン
<%= link_to "New Post", new_post_path, data: { turbo_frame: "modal" } %>
<turbo-frame id="modal"></turbo-frame>
無限スクロール
<div id="posts"><%= render @posts %></div>
<% if @posts.next_page? %>
<turbo-frame id="pagination" src="<%= posts_path(page: @posts.next_page) %>" loading="lazy">
<p>Loading more...</p>
</turbo-frame>
<% end %>
アンチパターン
| アンチパターン | 問題 | 解決策 |
|---|---|---|
| フレーム ID の不一致 | エラーが通知されずに失敗します | ID が一致することを検証します |
| ステータスコードの欠落 | Turbo がレスポンスを無視します | 422/303 を正しく使用します |
| ブロードキャストでの暗黙的なローカル変数 | 実行時エラー | 常に request_id: nil を渡します |
デバッグ
Turbo.setDebug(true)
document.addEventListener("turbo:frame-missing", (e) => console.error("Frame not found:", e.detail.response))
出力形式
Hotwire の機能を実装する際は、次の項目を提示してください。
- コントローラー - 適切なレスポンス処理を備えたアクション
- ビュー - フレームとストリームを含む HTML/ERB
- モデル - リアルタイム処理が必要な場合のブロードキャストコールバック
- JavaScript - 必要に応じた Stimulus コントローラー
コメント
Markdown 対応