Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第4章 サンプルアプリの仕様

この章のねらい

本書では、1 つの Rails アプリケーションを最初から最後まで育てながら Hotwire を学びます。題材は、チーム向けタスク管理アプリ Relayです。

この章では、Relay の題材を選んだ理由、何を作って何を作らないか、モデルと画面の構成、そして各部でどこを Hotwire 化していくかを共有します。コードはまだ書きません。先に全体像を持っておくことで、以降の章で「いま何のためにこの機能を使っているのか」を見失わずに済みます。

4.1 題材の選定

Hotwire を学ぶ題材には、次の条件がそろっていると都合がよいです。

  • 一覧画面があり、検索や絞り込みが自然に登場する
  • データ件数が多く、ページネーションの必要が出てくる
  • レコードに状態(ステータス)があり、バリデーションが意味を持つ
  • 複数のユーザーが同じ画面を見て、リアルタイム更新が活きる

ToDo アプリでは薄すぎ、SNS のような題材では発散しすぎます。その中間にあるのがタスク管理です。プロジェクトの下にタスクがぶら下がり、タスクにステータス・担当者・タグ・コメントが付く、という構造は、上の条件をすべて自然に満たします。

そこで本書では、チーム向けタスク管理アプリ Relay を育てます。

4.2 題材に必要な条件

4.1 で挙げた条件を、Relay のどの要素が満たすかを対応させておきます。

必要な条件Relay での実現
一覧+検索タスク一覧をキーワード・ステータス・タグで絞り込む
件数の多さseed で約 150 件のタスクを投入し、ページネーションを学ぶ
ステータス遷移タスクの statustodo / in_progress / done)を切り替える
複数ユーザー同じタスクを複数人が開き、コメントや更新をリアルタイムに共有する

この 4 点が、第7部「実務で使う Hotwire UI パターン」の題材にそのままつながります。

4.3 本書でやること / やらないこと

実務アプリを丸ごと作ろうとすると、Hotwire と関係のない作り込みが増え、学習の焦点がぼやけます。本書では、Hotwire を理解するうえで意味のある範囲に絞ります。何を捨てたかをはっきりさせておきます。

要素本編での扱い理由
認証入れる(最小)current_user が担当者、コメント投稿者、broadcast 範囲に必要になるため。Rails 標準の認証機能を使う。
認可本編は最小、深掘りは第31章単一チーム前提にして、Pundit などの認可ライブラリは持ち込まない。
マルチテナント / メンバー管理入れないMembership を入れると認可が重くなるため。1 チーム全員が同じプロジェクトを見られる前提にする。
タグ入れる(第23章で UI 化)検索と絞り込みに必要。初期 CRUD ではなく、必要になった章で導入する。
担当者入れる実務的なフィルタ、表示、broadcast の文脈に必要。Task から User への nullable 参照に留める。
コメント入れる(UI は第16章以降)Turbo Streams とリアルタイム更新の主役。モデルは第5章で用意し、UI は後で育てる。
通知永続化しない本編では Action Cable による即時通知に限定する。永続 Notification モデルは付録候補にする。

このうち「入れるが UI は後で作る」もの(タグ・コメント)があるのは意図的です。最初からすべての画面を作り込むと、Hotwire の各機能を「なぜ使うのか」が見えにくくなります。必要になった章で初めて UI を足すことで、機能を使う動機が明確になります。

4.4 モデル構成

Relay のモデルは次の 6 つです。関連は素直で、Rails の学習者がつまずかない範囲に収めています。

モデル主な属性役割
Username, email_address, password_digestログインユーザー、担当者、コメント投稿者
Projectname, descriptionタスクをまとめる単位
Taskproject_id, title, description, status, assignee_id, due_on本書の中心リソース
Commenttask_id, user_id, bodyTurbo Streams と broadcast の題材
Tagname検索・絞り込みの題材
Taggingtask_id, tag_idTaskTag の中間モデル

関連をまとめると次のとおりです。

  • Project は複数の Task を持ちます。
  • Task は複数の Comment を持ちます。
  • TaskTagging を介して複数の Tag と多対多です。
  • Task は担当者として User を 1 人持ちます(未割り当ても許します)。
  • Comment は投稿者として User を 1 人持ちます。

Relay のモデル関連と主要画面の対応図

Task#statustodoin_progressdone の enum にします。ステータスは検索、絞り込み、バリデーション、表示の出し分け、通知のすべてに使えるため、本書のハンズオンを支える軸になります。

なお User は Rails 標準の認証ジェネレータ(bin/rails generate authentication)で作ります。このジェネレータは UserSession を中心に、認証に必要な一式(コントローラ・ビュー・ルーティング・マイグレーション・bcrypt の導入)をまとめて生成します。これらは認証インフラなので、上表の Relay のドメインモデル(ProjectTask など)とは区別して扱います。

具体的には、現在のユーザーを保持する Current、ログインを扱う SessionsController、パスワード再設定の PasswordsController、認証ヘルパーをまとめた concern、再設定メール用の PasswordsMailer なども生成されます。

また、生成直後の Useremail_addresspassword_digest を持ちますが name は含まないため、本書では生成後に name を追加します。詳しい手順は第5章で扱います。

4.5 主要画面

Relay の主要画面に Turbo Drive、Frames、Streams、Stimulus、Action Cable を対応づけた図。

Relay の主要な画面と、そこで主に使う Hotwire の技術を対応させると次のようになります。どの画面でどの技術を使うかは、第3部以降で 1 つずつ実装していきます。

画面役割主に使う技術
プロジェクト一覧 / 詳細入口、通常のページ遷移の題材Turbo Drive
タスク一覧(リスト / ボード)検索、絞り込み、ページネーションTurbo Frames + Stimulus
タスク詳細(サイドバー)遅延読み込み、タブTurbo Frames
タスク作成 / 編集バリデーション UX、モーダルTurbo Frames + Turbo Streams + Stimulus
コメント欄追記、削除、リアルタイム更新Turbo Streams + Action Cable
通知トースト / flash操作結果、他者の更新Turbo Streams + Stimulus + Action Cable

ここで大切なのは、1 つの画面が複数の技術の組み合わせでできていることです。Hotwire は「どれか 1 つを選ぶ」ものではなく、画面の要件に応じて使い分けるものだと、この表が示しています。

4.6 Hotwire 化するポイント

Relay は、まず通常の Rails の CRUD として作ります(第5章)。その時点では、画面遷移のたびにページ全体が再描画される、ごく普通の Rails アプリです。

そこから、次のような順序で段階的に Hotwire 化していきます。

  1. ページ遷移とフォーム送信を Turbo Drive で速く見せる(第3部)
  2. タスクの一覧・詳細・編集を Turbo Frames で部分更新する(第4部)
  3. 作成・更新・削除・コメントを Turbo Streams で画面遷移なしに反映し、リアルタイム更新まで広げる(第5部)
  4. サーバーとのやり取りが要らない振る舞いを Stimulus で足す(第6部)
  5. 検索・ページネーション・モーダル・通知など、実務的な UI に仕上げる(第7部)

重要なのは、いきなり完成形を作らないことです。通常の Rails アプリを出発点にして、「ここはページ全体を再描画しなくてよいはずだ」と気づいた箇所を、必要な技術で置き換えていきます。この進め方そのものが、実務で Hotwire を導入するときの考え方になります。

4.7 各部との機能対応表

本書のどの部で、Relay のどこを作る・変えるかを一覧にします。読んでいる途中で「いま全体のどこにいるのか」を見失ったら、この表に戻ってください。

Relay で作る / 変える対象主な技術
第3部 Turbo Driveプロジェクト / タスクのページ遷移とフォーム送信Turbo Drive
第4部 Turbo Framesタスクのインライン編集、サイドバー詳細の遅延読み込みTurbo Frames
第5部 Turbo Streamsコメント追記・削除、タスクの作成・更新・削除、件数更新、Cable 配信Turbo Streams + Action Cable
第6部 Stimulusタスクフォームの補助、ドロップダウン、文字数、確認 UIStimulus
第7部 UI パターンタスクの検索・絞り込み、ページネーション、フォーム UX、モーダル / タブ / ドロップダウン、通知トースト総合
第8部 保守System Test、デバッグ、N+1、認可とセキュリティ横断
第9部 NativeRelay をネイティブシェルで包むHotwire Native
第10部 選定Relay を題材にアンチパターンと SPA 比較を振り返る採用判断

第7部の章ごとの内訳(どの章で検索を作り、どの章でモーダルを作るか)は、第7部の各章で詳しく示します。

4.8 完成形の操作ストーリー

完成した Relay を、ユーザーの操作の流れで見てみます。これがゴールのイメージです。

  1. ログインすると、プロジェクト一覧が表示されます。リンクをたどってもページ全体は再読み込みされず、画面が一瞬で切り替わります(Turbo Drive)。
  2. プロジェクトを開くと、タスクの一覧が出ます。上部の検索ボックスにキーワードを入れると、一覧だけがその場で絞り込まれ、URL にも条件が反映されます。共有してもリロードしても同じ結果が出ます(Turbo Frames + Stimulus)。
  3. 一覧をスクロールすると、続きのタスクが追加で読み込まれます(ページネーション)。
  4. タスクの行で「編集」を押すと、その行だけがフォームに変わります。入力が不正なら、ページ遷移せずにエラーがその場に表示されます(Turbo Frames + バリデーション UX)。
  5. 「新規作成」を押すとモーダルが開きます。保存すると、モーダルが閉じ、一覧の先頭に新しいタスクが追加され、件数も更新されます(Turbo Streams)。
  6. タスクを開いてコメントを書くと、同じタスクを見ている他のメンバーの画面にも、リアルタイムでコメントが追加されます(Action Cable)。
  7. 操作のたびに、画面の隅にトーストが出て、少し経つと自動で消えます(Turbo Streams + Stimulus)。

この一連の操作は、すべてサーバーが HTML を返すことで実現します。JSON を組み立ててクライアントで描画する、という作りにはなっていません。これが HTML over the wire の体験です。

4.9 本書で採用する JavaScript 構成

Rails で JavaScript を扱う方法はいくつかありますが、本書では importmap を基本にします。

importmap は Rails の標準構成で、ビルド工程(npm や bundler 相当の JavaScript ビルド)を必要としません。学習者の環境差を最小化でき、Hotwire の本質に集中できます。

一方で、外部の npm パッケージを本格的に使う場合は jsbundling 構成が向く場面もあります。本書では第22章「外部ライブラリと連携する」で、importmap での外部ライブラリの読み込み方を扱います。構成そのものの詳しい比較は第6章で行います。

この章で決めたモデル名・画面名・ステータス値は、以降のすべての章で参照します。手を動かす前に、Task#statustodo / in_progress / done であること、タグとコメントの UI は後の章で作ることだけは覚えておいてください。

参考資料