TurbolinksからTurboへの移行完全ガイド:Hotwireで実現する高速なRailsアプリ
Turbolinksは、Webアプリケーションのページ遷移を高速化する優れたツールでしたが、現在では活発な開発が終了しています。その後継として登場したのが、Hotwireファミリーの一部である「Turbo」という新しいフレームワークです。
開発チームは、Turbolinksから抽出されたコンセプトを、フレーム、フォーム送信、ネイティブアプリなど、より高速なWebを実現するためのさまざまな機能に応用できると考えました。
この記事では、Turbolinksの後継であるTurboフレームワークについて解説し、Turbolinksで最も重要かつ頻繁に使われていた機能をTurboでどのように扱うのかを、実践的な移行ガイドとして紹介します。
記事の内容をより深く理解するために、Turbolinksに関する基礎知識があると役立ちます。詳細については公式ドキュメントなどを参照してください。
Turboの紹介
Turboは、少ないJavaScriptでモダンかつ高速なWebアプリを構築するための複数のテクニックを集めたものです。サーバー側ですべてのロジックを処理し、その結果をHTMLの形式でブラウザに直接配信することでこれを実現します。ブラウザ側の責務は、プレーンなHTMLを処理するだけになります。
この仕組みを実現するため、Turboは以下の4つの主要パートに分かれています。
- Turbo Drive: Turboの中核となる機能です。リンクやフォームへのクリックを自動的にインターセプトしてフルページリロードを回避し、History APIでURLを変更、Ajaxでバックグラウンドからページをリクエストし、レスポンスを適切にレンダリングします。
- Turbo Frames: ページのサブセット(部分領域)を独立して扱うための機能です。ページを独立したコンテキストの集合に分解し、それぞれに個別のスコープと遅延読み込み(Lazy Load)機能を持たせます。
- Turbo Streams: WebSocket経由の非同期配信による部分的なページ更新を、シンプルなCRUDコンテナタグのセットで置き換えます。同じWebSocketを通じてHTMLフラグメントを送信でき、ページ側がそれを理解してUIを再処理します。
- Turbo Native: iOS/Android向けにネイティブ化する場合に、ネイティブシェルに埋め込まれたWebアプリでTurboを扱うためのツール群を提供します。
プロジェクトのセットアップ
作業をスムーズに進めるため、scaffoldで生成した投稿フォームの一連のフローを組み込み、Bootstrapでスタイリング済みの、すぐに使えるRailsアプリプロジェクトを用意しました。
これにより、環境構築に時間をかけることなく、Turbolinksが自動的に追加された動作するプロジェクトから始められます。すでに自分のプロジェクトをお持ちの場合でも、この記事の手順にはそのまま従えます。
railsコマンドを使って、新しいscaffold付きのRailsアプリを生成することも可能です。
リポジトリのGitHubリンクから取得できます。ローカルにクローンしたら、bundle installコマンドを実行してRailsの依存関係をすべてインストールしてください。
セットアップが完了したら、rails sコマンドでRailsサーバーを起動し、/postsのURIにアクセスしてみましょう。以下のような画面が表示されます。

RailsでのPosts CRUD
Turbolinksの機能を実際に確認するには、新規投稿作成や個別表示へのリンクをクリックしてページ間を移動してみてください。ページが再読み込みされることなくURLだけが変化することがわかります。
移行手順
まずはNodeパッケージの適切なインストールから始めましょう。turbolinksはもう不要なので、Nodeの依存リストから削除し、代わりにturbo-railsを追加します。以下の2つのコマンドを実行してください。
yarn remove turbolinks
yarn add @hotwired/turbo-rails
Railsを使用している場合、すべてが正しくインストールされたことを確認するもう一つの方法として、次のコマンドを実行します。
rails turbo:install
このコマンドは、アプリケーションにWebpackerがインストールされている場合(今回のプロジェクトではインストール済み)に、npm経由でTurboをインストールします。また、見落としがあった場合に備えて、古いTurbolinksの依存関係をプロジェクトから削除する処理も行われます。
次に、app/javascript/packs/application.jsファイルを開き、以下のコードを見つけてください。
import Turbolinks from "turbolinks";
Turbolinks.start();
なお、importの書き方はRailsアプリのバージョンによって多少異なる場合があります(古いバージョンではrequireが使われていました)。ただし、手順自体はどちらでも同じです。
これらを以下のコードに置き換えます。
import "@hotwired/turbo-rails";
そう、たった1行のimportだけでOKです。何かを手動で起動する必要はありません。import時にTurboインスタンスが自動的にwindow.Turboオブジェクトに割り当てられるため、管理も容易になっています。
Turboのみが読み込まれ、Turbolinksが残っていないことを確認するため、ファイルの末尾に以下のコードスニペットを追加してみましょう。
$(document).on("turbolinks:load", () => {
console.log("turbolinks!");
});
$(document).on("turbo:load", () => {
console.log("turbo!");
});
ブラウザでページを再読み込みした後、コンソールログに何が出力されるか確認してください。

Turboのloadイベントログの確認
もう一つ、app/views/layouts/application.html.erbファイルに必要な変更があります。これは基本的に、古いTurbolinksのdata属性をTurboの同等の属性に変更するというものです。data-turbolinks-*属性を使っている2つのタグを見つけ、以下のように置き換えてください。
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbo-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbo-track': 'reload' %>
これにより、Turboがheadタグ内のすべてのアセットを自動的に追跡し、変更があった場合に確実に再読み込みできるようになります。そこに追加されたすべてのスクリプトやスタイルを含む、すべてのファイルに適用されます。
Turboの機能を探る
Turboはアプリケーション内のすべてのリンクを自動的にインターセプトしてリロードなしで呼び出すため、特定のリンクに対してこの機能を無効化したい場合は、明示的にコーディングする必要があります。
試してみましょう。app/views/posts/index.html.erbファイルの「New Post」ボタンを以下のように更新します。
<%= link_to 'New Post', new_post_path, :class => "btn btn-primary btn-sm", "data-turbo" => "false" %>
ここでは、新しいdata属性data-turboを明示的に追加し、この特定のリンクがクリックされてもTurboが介入しないように指定しています。
アプリを再読み込みして「New Post」ボタンをクリックすると、通常のアプリと同じようにページ全体が再読み込みされることがわかります。
これは、Turboが正しく設定され、アプリケーションで動作しているかをテストする良い方法でもあります。
フォームについても同様です。Turboはすべてのフォーム送信を自動的に処理し、非同期で実行します。app/views/posts/_form.html.erbファイル内のフォームでこれを無効化したい場合は、送信ボタンを以下のように変更します。
<div class="actions">
<%= form.submit class: "btn btn-primary btn-sm", "data-turbo" => false %>
</div>
アプリを再読み込みしてテストしてみてください。新規投稿作成時にも同じ挙動が確認できます。
フォーム送信
Turboはリンクと非常によく似た方法でフォームを扱います。しかし、フォームのリクエストが常に成功するとは限りません。
実際に見てみましょう。まず、投稿のnameとtitleプロパティを必須にするバリデーションを追加します。app/models/post.rbファイルを開き、以下のように変更してください。
class Post < ApplicationRecord
validates :name, presence: true
validates :title, presence: true
end
アプリを再読み込みし、すべてのフィールドを空のまま新規投稿を追加しようとしてみてください。何も起こらないことに気づくでしょう。ブラウザのコンソールを確認すると、以下のようなメッセージが表示されます。

フォームのレスポンスは別の場所へのリダイレクトが必要
これを修正するには、2つのアプローチがあります。1つ目は、投稿コントローラーの各更新アクション(POST、PUTなど)にstatusを追加し、unprocessable entityオブジェクトを値として渡す方法です。
以下に、createメソッドとupdateメソッド(post_controller.rb)のコード変更を示します。
# def create
format.html { render :new, status: :unprocessable_entity }
# def update
format.html { render :edit, status: :unprocessable_entity }
編集を保存してフォームを再度テストすると、今度はエラーが正しく表示されます。

UIへのバリデーションエラーの表示
2つ目の方法は、turbo_frame_tagを使う方法です。Turboを使用するRailsアプリでは、前述のTurbo Framesはこのタグによってレンダリングされます。
ページの一部を切り離し、バックエンドアプリとの直接的なトンネルを開いて、Turboがリクエストとレスポンスをこの特定のフレームに関連付けられるようにしたい場合に、非常に便利な機能です。
試してみるには、まず_form.html.erbファイルの内容全体をこのタグで囲む必要があります。
<%= turbo_frame_tag post do %>
...
<% end %>
フォームの場合、postを渡す理由は明白ですね。ブラウザに戻って再度テストすると、期待通りに同じバリデーションエラーが表示されます。
ここでもう一つ注目すべき点は、このフォーム用に生成されるHTMLです。見てみましょう。
<turbo-frame id="new_post">
<form action="/posts" accept-charset="UTF-8" method="post">
...
</form>
</turbo-frame>
このカスタムHTML要素こそが、Turboがフレームベースのアクションとページ全体ベースのアクションを区別する仕組みです。
プログレスバー
ブラウザのデフォルトの読み込みメカニズムを取り除いた場合、ページの読み込みが遅いケースに備えて別の仕組みを提供するのが一般的です。
Turboには、BootstrapやMaterial Designなどの主要ライブラリが提供するものとよく似た、CSSベースのプログレスバーがページ上部に組み込まれています。
デフォルトでは、リクエストの処理に500ミリ秒以上かかった場合にのみ表示されるよう設定されています。今回のテストプロジェクトでは十分に短い時間です。
スタイルを変更したり、完全に削除したりしたい場合は、.turbo-progress-bar CSSクラスを調整してみてください。以下に例を示します。
.turbo-progress-bar {
height: 15px;
background-color: gold;
}
テストするには、application.jsファイルでプログレスバーの遅延時間を短縮する必要があります。以下のコードを追加してください。
window.Turbo.setProgressBarDelay(1);
指定する時間の単位はミリ秒です。以下は、更新されたプログレスバーの表示例です。

更新されたプログレスバーの表示
まとめ
Turboとその素晴らしい機能、特にStreamsモジュールやNativeモジュールについては、まだ語り尽くせていないことがたくさんあります。しかし、記事の焦点を保つため、今回はこれらの導入ステップにとどめます。
最後に、公式のTurboハンドブックをおすすめしておきます。筆者自身、この移行プロセス全体を始めたときに非常に役立ちました。プロジェクト固有の特殊な条件に対応するために必要な情報がすべて揃っています。
例えば、アプリでDeviseを使用している場合、いくつかの調整が必要になる可能性が高いでしょう。幸い、TurboチームはDeviseとTurboを組み合わせる際の細かな課題を解決するための優れたチュートリアルを公開しています。
-
GmailからOffice365への移行
新しい企業は通常、さまざまな規模の個人や組織のニーズに応える主要な電子メールシステムとしてGmailから始めます。ビジネスの成長に伴い、要件がより複雑になり始めた後、Office 365に移行し、エンタープライズレベルの用途へのOffice365の適合性を実現します。特に企業の世界では、Office365はビジネスの生産性を高めるための頼りになる製品です IMAPメールボックスをOffice365に移動するには、さまざまな移行方法があります。移行するメールボックスの数が少ない場合は、PSTファイルをGmail(Outlookの場合)からOffice 365(Outlookの場合)にエクスポ
-
Motorola Droid TurboでSIMカードを挿入・取り外す方法【工具なしでもOK】
Verizon版のDroid TurboやDroid Turbo 2を購入したものの、SIMカードの挿入・取り外し方法がわからずお困りではありませんか?本記事では、Motorola Verizon Droid Turbo 2のSIMカードおよびSDカードの取り扱いについて、専用ツールを使う場合と使わない場合の両方の手順をわかりやすく解説します。 Motorola Droid TurboからSIMカードを取り外す方法 安全に作業を行うために、まず以下の注意点を必ず確認してください。 SIMカードやSDカードをスマートフォンに挿入・取り外す際は、必ず電源をオフにしてください。 SIM/SDカード