edge
詳細はrubyonrails.orgで: もっとRuby on Rails

RailsでJavaScriptを使用する

このガイドでは、JavaScriptの機能をRailsアプリケーションに統合するためのオプションについて説明します。外部のJavaScriptパッケージの使用方法や、RailsでTurboを使用する方法などについても説明します。

このガイドを読み終えると、以下のことがわかるようになります。

1 Import Maps

Import mapsを使用すると、ブラウザから直接バージョン管理されたファイルに対応する論理名を使用してJavaScriptモジュールをインポートできます。Import mapsはRails 7からデフォルトで使用され、トランスパイルやバンドルの必要なく、ほとんどのNPMパッケージを使用してモダンなJavaScriptアプリケーションを構築できます。

Import mapsを使用するアプリケーションでは、Node.jsYarnは必要ありません。JavaScriptの依存関係を管理するためにRailsとimportmap-railsを使用する予定がある場合、Node.jsやYarnをインストールする必要はありません。

import mapsを使用する場合、別個のビルドプロセスは必要ありません。bin/rails serverでサーバーを起動するだけで使用できます。

1.1 importmap-railsのインストール

Rails 7以降の新しいアプリケーションには、Importmap for Railsが自動的に含まれていますが、既存のアプリケーションに手動でインストールすることもできます。

$ bin/bundle add importmap-rails

インストールタスクを実行します。

$ bin/rails importmap:install

1.2 importmap-railsでのNPMパッケージの追加

import mapを使用したアプリケーションに新しいパッケージを追加するには、ターミナルからbin/importmap pinコマンドを実行します。

$ bin/importmap pin react react-dom

その後、通常通りapplication.jsにパッケージをインポートします。

import React from "react"
import ReactDOM from "react-dom"

2 JavaScriptバンドラーを使用したNPMパッケージの追加

Import mapsは新しいRailsアプリケーションのデフォルトですが、従来のJavaScriptバンドリングを希望する場合は、esbuildwebpack、またはrollup.jsのいずれかを選択して新しいRailsアプリケーションを作成できます。

新しいRailsアプリケーションでimport mapsの代わりにバンドラーを使用するには、rails new--javascriptまたは-jオプションを渡します。

$ rails new my_new_app --javascript=webpack
または
$ rails new my_new_app -j webpack

これらのバンドリングオプションには、シンプルな設定とjsbundling-rails gemを介したアセットパイプラインとの統合が付属しています。

バンドリングオプションを使用する場合は、開発用にRailsサーバーを起動し、JavaScriptをビルドするためにbin/devを使用します。

2.1 Node.jsとYarnのインストール

RailsアプリケーションでJavaScriptバンドラーを使用する場合、Node.jsとYarnをインストールする必要があります。

インストール手順はNode.jsのウェブサイトで確認し、次のコマンドで正しくインストールされていることを確認します。

$ node --version

Node.jsランタイムのバージョンが表示されるはずです。バージョンが8.16.0よりも新しいことを確認してください。

Yarnをインストールするには、Yarnのウェブサイトのインストール手順に従います。次のコマンドを実行すると、Yarnのバージョンが表示されるはずです。

$ yarn --version

1.22.0などと表示されれば、Yarnは正しくインストールされています。

3 Import MapsとJavaScriptバンドラーの選択

新しいRailsアプリケーションを作成する際には、import mapsとJavaScriptバンドリングソリューションのどちらを選択するかを選択する必要があります。すべてのアプリケーションには異なる要件があり、大規模で複雑なアプリケーションでは、別のオプションに移行することが時間のかかる場合があるため、要件を慎重に考慮する必要があります。

Import mapsはデフォルトのオプションです。Railsチームは、import mapsが複雑さを減らし、開発者のエクスペリエンスを向上させ、パフォーマンスの向上に貢献する可能性を信じています。

多くのアプリケーション、特にJavaScriptのニーズに主にHotwireスタックを依存しているアプリケーションでは、import mapsが長期的な選択肢となるでしょう。Rails 7でimport mapsをデフォルトにする理由については、こちらをご覧ください。

他のアプリケーションでは、従来のJavaScriptバンドラーが必要な場合があります。以下の要件がある場合は、従来のバンドラーを選択する必要があります。

  • JSXやTypeScriptなどのトランスパイルが必要な場合
  • CSSを含むJavaScriptライブラリやWebpack loadersに依存する場合
  • tree-shakingが必要な場合
  • cssbundling-rails gemを介してBootstrap、Bulma、PostCSS、またはDart CSSをインストールする場合。このgemが提供するTailwindとSass以外のすべてのオプションは、rails newで別のオプションを指定しない場合、自動的にesbuildをインストールします。 ターボ -----

インポートマップを選ぶか、伝統的なバンドラを選ぶかにかかわらず、RailsはTurboを搭載しています。これにより、アプリケーションの速度が向上し、書く必要があるJavaScriptの量が劇的に減少します。

Turboは、従来のフロントエンドフレームワークに代わるものとして、サーバーがHTMLを直接配信することができます。これにより、RailsアプリケーションのサーバーサイドがJSON APIに過ぎない状態になるのを防ぎます。

3.1 Turbo Drive

Turbo Driveは、フルページのティアダウンと再構築を回避することでページの読み込みを高速化します。Turbo Driveは、Turbolinksの改良版であり、置き換えも可能です。

3.2 Turbo Frames

Turbo Framesは、ページの特定の部分を更新することなくリクエストに応じて更新することができます。

Turbo Framesを使用すると、カスタムJavaScriptなしでインプレース編集を行ったり、コンテンツを遅延ロードしたり、簡単にサーバーレンダリングされたタブ付きインターフェースを作成したりすることができます。

Railsは、turbo-rails gemを介してTurbo Framesの使用を簡素化するためのHTMLヘルパーを提供しています。

このgemを使用すると、次のようにしてTurbo Frameをアプリケーションに追加することができます。

<%= turbo_frame_tag dom_id(post) do %>
  <div>
     <%= link_to post.title, post_path(post) %>
  </div>
<% end %>

3.3 Turbo Streams

Turbo Streamsは、自己実行の<turbo-stream>要素で囲まれたHTMLのフラグメントとしてページの変更を配信します。Turbo Streamsを使用すると、他のユーザーが行った変更をWebSocketsを介してブロードキャストし、フォームの送信後にページの一部を更新することができます。

Railsは、turbo-rails gemを介してTurbo Streamsの使用を簡素化するためのHTMLとサーバーサイドのヘルパーを提供しています。

このgemを使用すると、コントローラーアクションからTurbo Streamsをレンダリングすることができます。

def create
  @post = Post.new(post_params)

  respond_to do |format|
    if @post.save
      format.turbo_stream
    else
      format.html { render :new, status: :unprocessable_entity }
    end
  end
end

Railsは、.turbo_stream.erbビューファイルを自動的に検索し、そのビューを見つけた場合にはそのビューをレンダリングします。

Turbo Streamのレスポンスは、コントローラーアクション内でインラインでレンダリングすることもできます。

def create
  @post = Post.new(post_params)

  respond_to do |format|
    if @post.save
      format.turbo_stream { render turbo_stream: turbo_stream.prepend('posts', partial: 'post') }
    else
      format.html { render :new, status: :unprocessable_entity }
    end
  end
end

最後に、Turbo Streamsは、モデルやバックグラウンドジョブからビルトインのヘルパーを使用して開始することもできます。これらのブロードキャストは、WebSocket接続を介してすべてのユーザーにコンテンツを更新するために使用することができます。これにより、ページのコンテンツが新鮮に保たれ、アプリケーションが活気づけられます。

モデルからTurbo Streamをブロードキャストするには、次のようにモデルコールバックを組み合わせます。

class Post < ApplicationRecord
  after_create_commit { broadcast_append_to('posts') }
end

これにより、次のように更新を受け取るページにWebSocket接続が設定されます。

<%= turbo_stream_from "posts" %>

4 Rails/UJSの機能の代替

Rails 6には、UJS(Unobtrusive JavaScript)と呼ばれるツールが搭載されています。UJSを使用すると、<a>タグのHTTPリクエストメソッドをオーバーライドしたり、アクションを実行する前に確認ダイアログを追加したりすることができます。Rails 7以前ではデフォルトでしたが、Turboを使用することが推奨されています。

4.1 メソッド

リンクをクリックすると常にHTTP GETリクエストが発生します。アプリケーションがRESTfulである場合、一部のリンクは実際にはサーバー上のデータを変更するアクションであり、GETリクエストでは実行されるべきではありません。data-turbo-method属性を使用して、そのようなリンクに明示的なメソッド("post"、"put"、"delete"など)を指定することができます。

Turboは、turbo-methodデータ属性を持つ<a>タグをスキャンし、指定されたメソッドを使用してデフォルトのGETアクションを上書きします。

例えば:

<%= link_to "Delete post", post_path(post), data: { turbo_method: "delete" } %>

これにより、次のように生成されます:

<a data-turbo-method="delete" href="...">Delete post</a>

data-turbo-methodを使用してリンクのメソッドを変更する代わりに、Railsのbutton_toヘルパーを使用することもできます。アクセシビリティの観点から、非GETアクションには実際のボタンやフォームを使用することが望ましいです。

4.2 確認

リンクやフォームにdata-turbo-confirm属性を追加することで、ユーザーに追加の確認を求めることができます。リンクをクリックするかフォームを送信すると、属性のテキストがJavaScriptのconfirm()ダイアログに表示されます。ユーザーがキャンセルを選択すると、アクションは実行されません。

例えば、link_toヘルパーを使用する場合:

<%= link_to "Delete post", post_path(post), data: { turbo_method: "delete", turbo_confirm: "Are you sure?" } %>

これにより、次のように生成されます:

<a href="..." data-turbo-confirm="Are you sure?" data-turbo-method="delete">Delete post</a>

ユーザーが「投稿を削除する」リンクをクリックすると、「本当に削除しますか?」という確認ダイアログが表示されます。

ただし、button_to ヘルパーと一緒にこの属性を使用する場合は、button_to ヘルパーが内部でレンダリングするフォームに追加する必要があります。

<%= button_to "Delete post", post, method: :delete, form: { data: { turbo_confirm: "本当に削除しますか?" } } %>

4.3 Ajax リクエスト

JavaScript から非 GET リクエストを行う場合、X-CSRF-Token ヘッダーが必要です。 このヘッダーがないと、リクエストは Rails によって受け入れられません。

注意: このトークンは、Rails によるクロスサイトリクエストフォージェリ(CSRF)攻撃を防ぐために必要です。セキュリティガイドを読んでください。

Rails Request.JS は、Rails に必要なリクエストヘッダーを追加するロジックをカプセル化しています。パッケージから FetchRequest クラスをインポートし、リクエストメソッド、URL、オプションを渡してインスタンスを作成し、await request.perform() を呼び出してレスポンスを処理します。

例:

import { FetchRequest } from '@rails/request.js'

....

async myMethod () {
  const request = new FetchRequest('post', 'localhost:3000/posts', {
    body: JSON.stringify({ name: 'Request.JS' })
  })
  const response = await request.perform()
  if (response.ok) {
    const body = await response.text
  }
}

Ajax コールを行うために別のライブラリを使用する場合は、セキュリティトークンをデフォルトのヘッダーとして自分で追加する必要があります。トークンを取得するには、アプリケーションビューで csrf_meta_tags によって出力される <meta name='csrf-token' content='THE-TOKEN'> タグを確認してください。次のようにすることができます。

document.head.querySelector("meta[name=csrf-token]")?.content

フィードバック

このガイドの品質向上にご協力ください。

タイポや事実の誤りを見つけた場合は、ぜひ貢献してください。 開始するには、ドキュメントへの貢献セクションを読んでください。

不完全なコンテンツや最新でない情報も見つかるかもしれません。 メインのドキュメントに不足しているドキュメントを追加してください。 修正済みかどうかは、まずEdge Guidesを確認してください。 スタイルと規約については、Ruby on Rails Guides Guidelinesを確認してください。

修正すべき点を見つけたが、自分で修正できない場合は、 問題を報告してください

そして最後に、Ruby on Railsのドキュメントに関するあらゆる議論は、公式のRuby on Railsフォーラムで大歓迎です。