[Rails]turboのカスタムアクションを使ってみる
はじめに
Turboは通常、7つの標準的なアクションがあります。
これらのアクションを使用することで、リアルタイムなページ更新や操作を実現できます。
- prepend: Turboフレーム内の特定の要素の前に新しい要素を追加します。
- append: Turboフレーム内の特定の要素の後ろに新しい要素を追加します。
- replace: Turboフレーム内の特定の要素を置き換えます。
- remove: Turboフレーム内の特定の要素を削除します。
- before: Turboフレームの前に新しいTurboフレームを挿入します。
- after: Turboフレームの後ろに新しいTurboフレームを挿入します。
- update: Turboフレーム内のコンテンツ全体を更新します。
これらのアクション以外に、StreamsAction
モジュールを使ってカスタムのアクションを作成することもできますのでいくつかの例を使って見ていきましょう。
ボタンのクリックに:
- 文字例を
append
するアクション -
console.log()
アクション - ブラウザ通知アクション
- ページのリダイレクトアクション
こちら四つのアクションを作成していきます。
StreamActions
のソースコード
環境
Rails 7.0.7
ruby 3.2.1
append
する
文字例を投稿の一覧にボタンーをクリックしたら、文字Hello Rails
を表示されるアクションを作ってみます。
turbo_stream
フォーマットを有効にする必要があります。
class PostsController < ApplicationController
def index
respond_to do |format|
format.turbo_stream
format.html
end
end
end
divの中に文字列を更新されるようにID
を用意します。
また、data: { turbo_stream: true }
がないとHTML
の処理になるので付け忘れないようにしましょう。
<%= button_to 'ボタンー', posts_path, method: :get, data: { turbo_stream: true } %>
<div id="hello_rails"></div>
アクションのリスポンスになるindex.turbo_stream.erb
を作成します。
<%= turbo_stream.append "hello_rails", plain: "Hello Rails!" %>
ログ:
20:48:06 web.1 | Started GET "/posts" for ::1 at 2023-09-09 20:48:06 +0900
20:48:06 web.1 | Processing by PostsController#index as TURBO_STREAM
20:48:06 web.1 | User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
20:48:06 web.1 | ↳ app/controllers/application_controller.rb:13:in `current_user'
20:48:06 web.1 | Post Load (0.2ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ? OFFSET ? [["LIMIT", 11], ["OFFSET", 0]]
20:48:06 web.1 | ↳ app/controllers/posts_controller.rb:6:in `index'
20:48:06 web.1 | User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? [["id", 1]]
20:48:06 web.1 | ↳ app/controllers/posts_controller.rb:6:in `index'
20:48:06 web.1 | Rendering posts/index.turbo_stream.erb
20:48:06 web.1 | Rendering text template
20:48:06 web.1 | Rendered text template (Duration: 0.0ms | Allocations: 4)
ブラウザのレスポンス:
クリックイベントに対して非同期的にページを更新して文字を表示させる例でした。
続いてStreamActions
モジュールを使ってアクションを作成してみます。
StreamActions
モジュールをインポートする
アクションを作成するためにStreamActions
モジュールをインポートします。
import { Turbo } from "@hotwired/turbo-rails"
const { StreamActions } = Turbo
console.log()
アクションを作成する
アクション名は分かりやすい名前console_log
をつけます。
this
キーワードはturbo_stream
フレーム中の要素にアクセスすることができます。
要素のmessage
属性を取得しconsole.log
で表示させてみます。
StreamActions.console_log = function(){
console.log(this.getAttribute("message"))
}
<%= turbo_stream_action_tag "console_log", message: "Hello World" %>
turbo_stream_action_tag
: これは Turbo Streams でカスタムアクションをトリガーするためのヘルパーメソッドです。第1引数にアクション名(ここでは "console_log"
)を指定し、第2引数にオプションを持つハッシュを指定します。
"console_log"
: これはカスタムアクションの名前です。先ほどのコードで定義したカスタム Turbo Stream アクションと対応しています。
message: "Hello World"
: カスタムアクションのオプションとして、"message" という名前の属性を持つことを指定しています。
application.js
に読み込みます。
import "./console_log"
ブラウザのリスポンス:
クリックイベントに対して非同期的にconsole.log()
を実行させる例でした。
ブラウザ通知アクション
次ではブラウザの通知APIを使って通知を送ってみます。
import { Turbo } from "@hotwired/turbo-rails"
const { StreamActions } = Turbo
StreamActions.notification = function(){
let title = this.getAttribute("title")
Notification.requestPermission(function(status){
console.log(status)
if (status == "granted"){
new Notification(title)
}
})
}
application.js
に読み込むことを忘れないようにしましょう。
<%= turbo_stream_action_tag "notification", title: "ブラウザからの通知だ!" %>
通知機能を試すには通知をON
にしてから試してください。
ブラウザからのレスポンス:
クリックイベントに対してブラウザから通知を受け取る例でした。
最後はページをリダイレクトさせるアクションを作ります。
ページのリダイレクト
import { Turbo } from "@hotwired/turbo-rails"
const { StreamActions } = Turbo
Turbo.StreamActions.redirect = function () {
const url = this.getAttribute('url') || '/'
Turbo.visit(url, { frame: '_top', action: 'advance' })
}
こちらもapplication.js
に読み込み込んでいきます。
コントローラー内でリダイレクトURLを指定するのでヘルパーメソッド内にredirect
メソッドを作成します。
rails g helper TurboStreams::Redirect
create app/helpers/turbo_streams/redirect_helper.rb
module TurboStreams::RedirectHelper
def redirect(url)
turbo_stream_action_tag("redirect", url: url)
end
end
Turbo::Streams::TagBuilder.prepend(TurboStreams::RedirectHelper)
Turbo::Streams::TagBuilder
クラスは、Turbo StreamsのHTMLタグ(フレームやストリーム要素など)を生成するためのユーティリティクラスです。
このクラスのメソッドを使用することで、Turbo Streamsに含まれる要素を生成し、Turbo Streamsを作成するためのturbo_stream
、turbo_frame
、turbo_stream_action
などのHTML要素を生成されます。
Turbo::Streams::TagBuilder
クラスにTurboStreams::RedirectHelper
モジュールのメソッドを追加します。
コントローラー内にTurboStreams
モジュールをinclude
し、メソッドを使えるようにします。
ルートURLにリダイレクトさせてみます。
include TurboStreams::RedirectHelper
class PostsController < ApplicationController
def index
respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.redirect(root_url) }
format.html
end
end
end
ボタンをクリックしてルートURLにリダイレクトされたことを確認します。
ブラウザからのレスポンス:
オプション
turbo_stream_action_tag
のオプションはこちらになります。
turbo_stream_action_tag(action, target: nil, targets: nil, template: nil, **attributes)
"action"
(必須): カスタムアクションの名前。これはカスタムJSコードで処理されます。
target: "element_id"
: アクションが影響を与えるHTML要素のID
。アクションが実行された場合、この要素が更新されます。
targets
(オプション): Turbo Streamsを適用する複数のHTML要素を指定する場合に使用します。targets
パラメータには配列で要素を指定します。
template
(オプション): Turbo Streamsのテンプレート名を指定します。テンプレートを指定すると、そのテンプレートが適用された要素がTurbo Streamsの一部として更新されます。
attributes
(その他のオプション): その他のHTML属性を指定できます。これにはdata
属性やカスタム属性などが含まれます。
これらのオプションを使って、Turbo Streams をカスタマイズし、クライアント側での動作や表示を制御することができます。
適切なオプションを選択して、Turbo Streams の挙動を調整してください。
終わりに
turboのカスタムアクションを使ってみました。
デフォルトのアクション以外にいくつでも定義できるところが便利でした。
ヘルパーメソッドと合わせて使うことによって再利用性も高いと感じました。
Discussion