SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Railsによるクライアントサイド開発入門

Rails 7×Hotwireで簡単にSPA開発! Turboの基本をチュートリアルとともに理解しよう

Railsによるクライアントサイド開発入門 第5回

  • X ポスト
  • このエントリーをはてなブックマークに追加

知らないうちに使っているかも? Turbo Driveの実態に迫る

 Hotwireは、デフォルトのアプリケーション構成でインストールされており、まずはTurbo Drive(以降Drive)の機能が有効になっています。このため、知らないうちにHotwireの恩恵に与っていたということもあるでしょう。このDriveの基本的な動作を見るために、まずはデフォルト構成のアプリケーションを作成して、動きを追ってみましょう。

アプリケーションの作成

 Hotwireの動作に集中するために、5つの--skip-xxxxオプションを指定して不要な機能は外してしまうことにします。

% rails new hotwire_app --skip-action-cable --skip-action-text --skip-action-mailer --skip-action-mailbox --skip-jbuilder

 次に、Scaffoldingで適当なモデル(日本語フィールドと英語フィールドからなるWordモデル)を作成し、新規作成ページでの動き(リクエストとレスポンス)を追ってみます。

% rails generate scaffold word japanese english
% rails db:migrate
% rails server

デベロッパーツールの準備

 Pumaサーバが起動したら、Webブラウザ(Google Chrome)を起動します。アドレスバーに「http://localhost:3000/words」と入力し、項目はまだありませんがWordモデルの一覧を表示させておきましょう。ここで、デベロッパーツール(DevTools)を[縦三点リーダー(Google Chromeの設定)]―[その他のツール]―[デベロッパー ツール]で開いておきます。ウインドウ右側にデベロッパーツールのパネルが展開されます。

[NOTE]デベロッパーツールの設定

 デベロッパーツールは、設定によってはウインドウ下側に配置されますが、今回は右側に配置した方が便利です。デベロッパーツールの[縦三点リーダー(Customize and controls DevTools)]アイコンから開くメニューから「固定サイド(Dock side)」の設定を変更してください。また、日本語化が可能なので、本稿では日本語化された状態を前提に解説を進めます。

 パネルが展開されたら、上部の「要素」「コンソール」……と並んでいるバーの[ネットワーク]をクリックしておきます。これで、表示がネットワークタブに切り替わり、ネットワーク上のやりとりを見ることができます(図1)。

図1 デベロッパーツール
図1 デベロッパーツール

アプリケーションの操作

 ここで、[New word]リンクをクリックして新規作成ページを表示させます(図2)。

図2 新規作成ページ
図2 新規作成ページ

 表示が欠けている部分もありますが、パネル下のリクエスト一覧(「名前」「ステータス」「タイプ」……と並んでいる欄)のタイプ列に注目してください。「fetch」「stylesheet」「script」「vnd.microsoft.icon」となっています。このうち、「fetch」はリクエストがFetch APIに基づくものという意味です(他は、CSS、JavaScript、Iconという意味)。この意味は後述するとして、表示された新規作成ページで各フィールドを適当に入力し、[Create Word]ボタンをクリックして作成を実行してください(図3)。

図3 作成を実行
図3 作成を実行

 すると、ページは項目追加後の詳細表示となり、リクエスト一覧にはさらに表示が増えます。今度は「fetch / リダイレクト」が追加され、さらに「fetch」が追加されます。ひとまず、新規作成までを行ってみました。

Driveの動作

 ここまでで、内部で何が行われているかを以下にまとめてみました。

  • [New Word]リンクのクリックで1回目のfetchリクエストが発生、新規作成ページが返される
  • 新規作成ページで項目を入力し[Create Word]ボタンのクリックで2回目のfetchリクエストが発生、項目の保存後にステータスコード302とともにリダイレクト先が返される
  • 3回目のfetchリクエストがリダイレクト先である「/articles/1」へ発生、追加した項目の詳細ページが返される

 デベロッパーツールのネットワークタブに現れた「fetch」とは、JavaScriptのFetch APIによる非同期リクエストを意味しています。Ajaxなどで用いられたXmlHttpRequest(XHR)の発展型と思っておけばよいでしょう。このように、Driveが有効な状態では、リンクやボタンのクリックで、通常のGETメソッドやPOSTメソッドのリクエストが発生するのではなく、Fetch APIによる非同期リクエストが発生します。

 Driveでは、基本的にアクションに応じてfetchリクエストを発行し、そのレスポンスでページ内容を更新します。このとき重要なのは、fetchリクエストなのでページの遷移は発生せず、レスポンスの内容で自らを書き換えて、URLも変更しているということです。

 これらの処理はDriveの以下の機能が使われています。

  • レスポンスはHTMLとなる。普通のAPI呼び出しのようなJSONではない
  • レスポンスからbody要素のみを取り出し、現在のページのbody要素をそれで置き換える
  • title要素やCSRF対策用トークンなどのhead要素の一部も書き換える
  • JavaScriptのHistory APIを使ってURLも更新する

[NOTE]Driveのその他の機能

 シンプルなデータでしかもローカルでアプリケーションを実行しているときには気付きにくいのですが、時間のかかるリクエスト(500ミリ秒以上)の待機中に表示されるプログレスバーの機能もあります。また、ページの内容をキャッシュしておきブラウザの[戻る][進む]で表示する機能、ページのリクエストが完了するまで暫定的にキャッシュの内容を表示しておくプレビューの機能もあり、良好なレスポンスに貢献しています。

 Driveは明示的に無効にしない限りデフォルトで有効なので、link_toメソッドで作成したリンクや、form_withメソッドで作成したフォームには、基本的にDriveが作用することになります。なお、Driveを含むTurboはJavaScriptライブラリであり、app/javascript/application.jsにおいてリストのように読み込まれています。

リスト app/javascript/application.js
import "@hotwired/turbo-rails"	Hotwireの読み込み
import "controllers"

Turboを無効にする

 Turboは無効にすることができますので、Turboが有効なときの動作と比べることで、Turboの基本的な動作がより理解できるでしょう。Turboは、app/javascript/application.jsに以下の行を記述すれば無効にできます。

リスト /app/javascript/application.js
Turbo.session.drive = false

 今回はfetchリクエストは発生しないはずなので、「フィルタ」と表示された検索ボックスの下の「ドキュメント」をクリックしておきます。これで、HTMLドキュメントのやりとりのみ表示できます。そして同じく、アドレスバーに「http://localhost:3000/words」と入力し、Wordモデルの一覧を表示させましょう。今度は、先ほど登録した1件が表示されていると思います。このとき、ネットワークタブのリクエスト一覧には、「タイプ」が「Document」であるリクエストが発生していることがわかります。これは、通常通りGETメソッドのリクエストが送られて、HTMLドキュメントが返されたことを意味しています(図4)。

図4 Turbo無効時に一覧ページを表示
図4 Turbo無効時に一覧ページを表示

 Drive有効時と同じ手順を進めます。[New Word]をクリックして新規作成ページを表示させます。するとリクエスト一覧がいったんクリアされて、改めて「タイプ」が「Document」であるリクエストが発生したことがわかります(図5)。Driveが有効なときはページ遷移は発生しないので、アクションによってfetchリクエストの状況が蓄積されていきますが、無効なときにはアクションのたびにリクエスト一覧がクリアされていきます。

図5 Turbo無効時に新規作成ページを表示
図5 Turbo無効時に新規作成ページを表示

 続けて、新規作成ページでフィールドを埋めて[Create Word]ボタンをクリックしてみても、リクエスト一覧がクリアされて同様のリクエストが発生していることがわかります(図6)。

図6 Turbo無効時に作成を実行
図6 Turbo無効時に作成を実行

 なお、ここではアプリケーション全体でTurboを無効にしましたが、リンクやフォーム単位で無効にすることもできます。link_toメソッドとform_withメソッドに「data: { turbo: false }」を指定してあげると、そのリンクとフォームではTurboが無効になります。

リスト app/views/words/index.html.erb(Turbo無効)
<%= link_to "New user", new_user_path, data: { turbo: false } %>

[NOTE]要素を更新の対象外とできるdata-turbo-permanent属性

 Driveではbody要素全体が置き換わるので、たとえば動画や音声などページの表示が完了した後でも動作している要素がある場合、ページ更新のたびに再生がリセットされては不自然です。このような要素にはdata-turbo-permanent属性を指定することで、更新の対象から外すことができます。注意が必要なのは、要素の識別のために必ずid属性を指定することです。

次のページ
ページの一部を指定して変更できるTurbo Frames

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Railsによるクライアントサイド開発入門連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/16790 2022/11/17 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング