Master Rails アクション ケーブル (ソリッド ケーブル付き):Redis を使用せずにリアルタイム アプリを構築
Web アプリケーションではリアルタイム機能がますます重要になってきていますが、すべての Rails 開発者がフレームワークの組み込み WebSocket ライブラリである Action Cable に精通しているわけではありません。
Rails Action Cable は長い間 Web ソケットをサポートしてきましたが、さらに複雑さが伴います。 Rails 8 ではソリッド ケーブルが導入されました 、Redis の必要性を排除する、Action Cable 用の新しいデータベース ベースのアダプターです。このガイドでは、Solid Cable を使用した Action Cable について説明し、リアルタイム機能を構築する方法を示します。 Redis を使用せずに、Rails 8 アプリにリアルタイム機能をいかに簡単に追加できるかがわかります。
フォローして一緒にアプリを構築することをお勧めしますが、GitHub で完成したプロジェクトをチェックすることも歓迎します。
Rails アクション ケーブルを使用する理由
最新の Web アプリでは、多くの場合、更新をリアルタイムでクライアントにプッシュする必要があります。わかりやすい例としては、即座に表示されるチャット メッセージやライブ ダッシュボード通知などが挙げられます。 アクション ケーブル は、WebSocket をアプリに統合するための Rails の組み込みソリューションで、サーバーとクライアント間の双方向の永続的な通信を可能にします。私は、Rails フレームワークの一部としての Action Cable に個人的に感謝しています。これは、本当に役立つ Web アプリに必要なものをすべて提供するという全体的なテーマをサポートしているからです。 Action Cable を使用すると、ブラウザが明示的に要求しなくても、サーバーがブラウザにデータを送信できることになります (ユーザーによる更新は必要ありません!)。
Action Cable と WebSocket を使用すると、Rails アプリは、これまでサーバーでレンダリングされたアプリに実装するのが難しかったライブ インタラクティブ機能を提供できます。この日常的な使用例は次のとおりです。
- ライブチャット アプリケーション
- 通知とフィード
- ライブアップデートを備えた共同アプリ
- スポーツ中継または株式相場
つまり、Action Cable は、従来の要求/応答サイクルとリアルタイムのイベント駆動型更新の間のギャップを橋渡しします。クライアント側では、Rails はチャネルにサブスクライブしてブロードキャストを受信するための JavaScript コンシューマーを提供します。開発者は、フロントエンド クライアントがサブスクライブできるバックエンド チャネル (コントローラに似ていますが、リアルタイム ストリーム用) を定義することにより、Action Cable と対話します。
ソリッド ケーブルとは何ですか?
以前の Rails バージョンで Action Cable を使用したことがある場合は、本番環境では通常、Redis (または PostgreSQL の NOTIFY) に依存していることをご存じかもしれません。 ) 異なるサーバープロセス間でメッセージをブロードキャストします。 pub/sub サービス (多くの場合 Redis) は、1 つの Rails プロセスからのメッセージが他のすべてのプロセスに確実に配信されるようにし、接続されている WebSocket クライアントにメッセージを転送できるようにします。この追加インフラストラクチャは、歴史的にアクション ケーブルを使用するための必須条件でした。
Rails 8 で導入された Solid Cable は、既存のデータベースをバックエンドとして使用することで、Redis のような外部パブリッシュ/サブスクライブ サービスの必要性を置き換えます。 Solid Cable は、Solid Queue for Active Job や Solid Cache for Active Cache と同様に、Action Cable 用のデータベース ベースのアダプターです。各受信 WebSocket メッセージはデータベース テーブルに書き込まれ、すべての Action Cable インスタンスはそのテーブルをポーリングして、クライアントにブロードキャストする新しいメッセージを探します。これは非常に迅速に (デフォルトでは 100 ミリ秒ごとに) 行われるため、ほぼリアルタイムのパフォーマンスが得られます。メッセージはプルーニングされるまでの短期間 (デフォルトでは 24 時間) のみ保存されるため、データベース容量を気にせずに最近の問題をデバッグできます。
全体として、Solid Cable は Rails 8 の「Solid Trifecta」の哲学に適合しています。これは、キャッシュ、バックグラウンド ジョブ、およびリアルタイム メッセージングのための、データベースに裏付けされた組み込み機能の完全なセットです。 Solid Cable を使用すると、データベース全体でジョブ、キャッシュ、WebSocket を実行するための最後の部分が得られます。
Solid Cable を使用した Rails 8 アプリの構築
おそらく Solid Cable を実際に使ってみることに興味があるでしょう。それでは、Solid Cable を Rails 8 アプリケーションに追加し、複数のユーザーがリアルタイムでメッセージを交換できる最小限のチャット ルームを構築する手順を見てみましょう。
サンプルアプリの作成
Solid Cable をバックエンドとして使用しながら、Action Cable の基礎 (チャンネル、サブスクリプション、ブロードキャスト) を学習します。この例では Rails 8 を使用するので、次の内容で新しい Rails アプリを作成してください。
rails _8.1.0_ new solid_cable_chat --database=sqlite3
次に、cd 新しいsolid_cable_chatディレクトリに移動します。
Rails 8 を使用しているため、作業を開始するために Solid Cable やその他の宝石を追加する必要はありません。構成の大部分またはすべてがそこにあります。 Rails の古いバージョンを使用している場合に備えて、すべての手順を説明します。
ソリッド ケーブルの構成
まず、Solid Cable セットアップを実行します。
bin/rails solid_cable:install
このジェネレーターは主に 2 つのことを行います。 config/cable.yml が作成されます Solid Cable をケーブル アダプターとして設定する構成ファイル。また、db/cable_schema.rb も作成されます。 このファイルには、Solid Cable のメッセージ テーブルのデータベース スキーマ定義が含まれています。 Rails の最近のバージョンでは、rails new の実行時にこれらのファイルも自動的に作成されます。 .
次に、Solid Cable のデータベース設定を構成する必要があります。デフォルトでは、Rails は Solid Cable 用に別のデータベースを使用して、リアルタイム メッセージング データを残りのデータから分離します。開発では、同じデータベースを使用することも、別のデータベースをセットアップすることもできます。開発中の Solid Cable 用に別の SQLite データベースを使用する方法を説明します。これは、新しい「ケーブル」データベース接続を追加することを意味します。
Solid Cable 用のデータベースのセットアップ
config/database.yml を開きます ファイル。開発セクションに、cable を追加します。 データベース。たとえば、SQLite (開発用の Rails のデフォルト) を使用している場合:
development:
primary:
<<: *default
database: storage/development.sqlite3
cable:
<<: *default
database: storage/development_cable.sqlite3
migrations_paths: db/cable_migrate
production:
primary:
<<: *default
database: storage/production.sqlite3
cache:
<<: *default
database: storage/production_cache.sqlite3
migrations_paths: db/cache_migrate
queue:
<<: *default
database: storage/production_queue.sqlite3
migrations_paths: db/queue_migrate
cable:
<<: *default
database: storage/production_cable.sqlite3
migrations_paths: db/cable_migrate
繰り返しになりますが、Rails の最新バージョンを使用している場合は、この構成はすでに存在します。
config/cable.yml を開きます。 。 Solid Cable は実稼働環境ではすでにデフォルトのアダプターになっているはずです。開発でも Solid Cable を有効にしたいと考えています (ローカルホストでチャットをテストできるように)。 cable.yml を編集します solid_cable を使用するには 開発中のアダプターを選択し、cable を指すようにします。 先ほど設定したデータベース:
development:
adapter: solid_cable
connects_to:
database:
writing: cable
polling_interval: 0.1.seconds
message_retention: 1.day
test:
adapter: test
production:
adapter: solid_cable
connects_to:
database:
writing: cable
polling_interval: 0.1.seconds
message_retention: 1.day
上記の cable.yml では 、開発アダプターを solid_cable に設定します。 そして実稼働設定から設定をコピーしました。 connects_to この設定は、Action Cable にケーブルを使用するように指示します。 データベース (database.yml で定義) ) メッセージを保存します。 Rails の最新バージョンでもこの変更を行う必要があります。
小規模なアプリの場合は、同じプライマリ データベースを使用して Solid Cable のテーブルを保持できます (スキーマを移行にコピーし、別の DB 構成を削除することによって)。ただし、プライマリ アプリ データに対する潜在的なパフォーマンス干渉を避けるために、別のデータベースを使用することをお勧めします。
最後に、rails db:prepare を実行します。 データベースの準備が整っていることを確認します。アプリを配布する場合は、実稼働環境でもこれを行う必要があります。
アクション ケーブル チャンネルのセットアップ
Action Cable は、データのストリームを処理する Ruby クラスであるチャネルを通じて動作します。これは、HTTP リクエストを処理するコントローラーに似ています。チャット機能用のチャネルを作成しましょう。これを UserChatChannel と呼びます。 。ジェネレーターを使用します。
rails generate channel UserChat
生成された app/channels/user_chat_channel.rb を開きます。 を更新し、新しいロジックを含めます。
クライアントが UserChatChannel にサブスクライブする場合 (チャット ページを開くことで)、subscribed コールバックが呼び出されます。 stream_from "user_chat_channel" を呼び出したいとします。 このコールバックでは、"user_chat_channel" という名前のブロードキャストからストリーミングを開始します。 .
本質的には、「user_chat_channel へのデータ ブロードキャストをリッスンする」と言っているのです。 ストリームして、このチャンネルのクライアントに渡します。」このチャンネルに登録しているすべてのユーザーは、"user_chat_channel" へのメッセージ ブロードキャストを受信します。 .
また、カスタム アクションを定義したいと思います。これを talk(data) と呼びます。 。チャネル内の任意のパブリック メソッドをクライアント側から呼び出すことができます。この場合、クライアントが perform("talk", { content: "Hello World" }) を呼び出すと、 、talk メソッドはサーバー上で実行されます。
talk の実装 クライアントから送信されたメッセージの内容を取得し、ActionCable.server.broadcast を使用します。 "user_chat_channel" に登録している全員に送信します 。これは、すべての加入者 (送信者を含む) がメッセージ データをリアルタイムで受信することを意味します。メッセージ テキストを含むハッシュをブロードキャストするだけです。必要に応じて、他の情報 (ユーザー名やタイムスタンプなど) を含めることもできます。 注: 実際のアプリでは、メッセージをデータベースに保存したり、ここで検証を実行したりすることもできます。簡単にするために、単にブロードキャストするだけです。
class UserChatChannel < ApplicationCable::Channel
def subscribed
stream_from "user_chat_channel"
end
def unsubscribed
# Any cleanup needed when unsubscribing from the channel
end
def talk(data)
message = data["content"]
ActionCable.server.broadcast("user_chat_channel", { content: message })
end
end
クライアント内でチャンネルのコンシューマーを構築する
バックエンドを構築したので、ユーザーが WebSocket 経由でメッセージを送受信できるようにフロントエンドを接続し、リアルタイム機能を実証する必要があります。
Rails 8 には、Action Cable の JavaScript 機能が組み込まれています。ジェネレーターは app/javascript/channels/user_chat_channel.js を作成しました。 私たちのためにファイルしてください。次にクライアントの動作を実装します。
app/javascript/channels/user_chat_channel.js を開きます それを次のように更新します。
import consumer from "channels/consumer";
const userChatChannel = consumer.subscriptions.create("UserChatChannel", {
connected() {
console.log("Connected to UserChatChannel.");
},
disconnected() {
console.log("Disconnected from UserChatChannel.");
},
received(data) {
const messagesDiv = document.getElementById("messages");
if (messagesDiv && data.content) {
const messageElement = document.createElement("p");
messageElement.textContent = data.content;
messagesDiv.appendChild(messageElement);
}
}
});
function sendMessage(content) {
userChatChannel.perform("talk", { content: content });
}
export { sendMessage };
window.sendMessage = sendMessage;
ここでは consumer.subscriptions.create("UserChatChannel", {...}) を使用します。 UserChatChannel へのサブスクリプションを作成するには サーバー上で。これにより、チャンネルとの対話に使用できるサブスクリプション オブジェクトが返されます。
connected() 接続が確立されるとコールバックが実行されます。ここでは、コンソールにログを記録するだけなので、コンソールが機能するかどうかを確認できます。
disconnected() WebSocket が切断されるとコールバックが実行されます。
received(data) コールバックは重要です!このコールバックは、チャネルがサーバーからブロードキャストを受信するたびに起動されます。 UserChatChannel#talk で { content: message } をブロードキャストします 。 data ここでの引数は同じハッシュになります。これにより、新しいメッセージが到着すると、接続されているすべてのクライアントのチャット ログが即座に更新されます。
ヘルパー sendMessage(content) も定義します。 userChatChannel.perform("talk", { content: ... }) を呼び出します 。これにより、サーバー側の talk にリクエストが送信されます。 ユーザーが入力したメッセージの内容を含む、定義したアクション。
ここで、ユーザーがメッセージを送受信するためのシンプルな UI が必要になります。このための非常に基本的なビューを作成しましょう。
サンプル アプリ用のシンプルな UI の構築
まず、コントローラを生成します。
rails generate controller UserChat index
次に、インデックス ビューを開いて、基本的な設定を行います。
<h1>Chats from Users</h1>
<div id="messages" style="border: 1px solid #ccc; padding: 1em; height: 200px; overflow-y: auto; margin-bottom: 1em;">
<!-- Messages will appear here -->
</div>
<form id="chat-form" onsubmit="event.preventDefault(); sendMessage(document.getElementById('chat-input').value); document.getElementById('chat-input').value = '';">
<input type="text" id="chat-input" placeholder="Type a message..." autocomplete="off" style="width: 80%;" />
<button type="submit">Send</button>
</form>
最後に、config/routes.rb でこの新しいルートを指すようにルート ルートを設定します。 :
root "user_chat#index"
すべてが連携してどのように機能するかを示す
シンプルなチャット アプリはテストの準備ができています。 bin/dev でプロジェクトを実行します。 localhost:3000 にアクセスしてください :

リアルタイムの更新を表示するには、2 つの異なるブラウザー タブでアプリを開きます。 1 つのタブに、「タブ番号 1 からこんにちは!」のようなメッセージを入力します。
2 番目のタブからメッセージを送信すると、そのメッセージが最初のタブに表示されることがわかります。

Rails Action Cable を本番環境にデプロイする
Solid Cable は WebSocket メッセージをデータベース テーブルに保存し、上記の例ではデフォルトの cable を使用しました。 データベース。 Rails 8 では、新しいアプリでも SQLite for Solid Cable をデフォルトで使用しますが、技術的には cable を追加することで、Rails がサポートする任意のデータベースをポイントすることができます。 config/database.yml のセクション .
実際、本番環境では Solid Cable 用に別のデータベースを使用することをお勧めします。 リアルタイム メッセージングの負荷を残りのデータから分離します。たとえば、専用の app_production_cable をプロビジョニングするとします。 プライマリ アプリ データは app_production に残りますが、Solid Cable のデータベースは保存されません。 .
この分離により、チャットや通知のトラフィックがメイン アプリケーションのクエリと競合するのを防ぎます。とはいえ、小規模なアプリの場合は、通常、アプリ データとケーブル メッセージの両方に単一のデータベースを使用しても問題ありません。
明らかではない部分は、Solid Cable データベースが展開設定に含まれていることを確認することです。別のデータベースを使用する場合は、必ず rails db:prepare を実行してください。 または rails db:migrate Rails が messages を作成するようにします。 本番環境のテーブル。
各 WebSocket 接続はサーバー メモリを消費するので、必要な接続数を処理するのに十分なリソースがサーバーにあることを確認してください。
ポーリング間隔の構成
Solid Cable のポーリング頻度は構成可能であり、待ち時間とデータベースの負荷のバランスをとることができます。間隔を短くするとポーリングの頻度が高くなり、新しいメッセージを取得する時間が短縮されますが、その代償としてデータベースに対する SELECT クエリが増加します。
逆に、間隔を長くするとデータベースの使用量は軽減されますが、ブロードキャストと更新の遅延が増加します。実際には、デフォルトの 0.1 秒 (1 秒あたり 10 ポーリング) が、ほとんどのデータベースに負荷をかけずに一見リアルタイムの更新を提供する適切な開始点です。
Solid Cable は、Solid Trifecta の重要な柱です
Rails Action Cable がリアルタイム通信のために WebSocket を Rails に導入する方法と、Solid Cable が Redis なしでそれをどのように可能にするかを見てきました。 Rails には他に 2 つの「ソリッド」 ライブラリがあることをご存知ですか? ? Solid Cache を使用すると、Redis を使用せずに簡単にキャッシュでき、Solid Queue を使用すると、Redis を使用せずにバックグラウンド ジョブを処理できます。
「Solid Trifecta」を使用すると、インフラストラクチャのオーバーヘッドを最小限に抑えてインタラクティブなアプリケーションを構築するための非常に機能的なフレームワークが得られます。
Solid Cable とその兄弟の主な利点は、シンプルさです。 Rails アプリのリアルタイム機能は、バックグラウンドでアプリのデータベースのみを使用してすぐに機能します。導入がより簡単になり (Redis や追加サービスが不要)、多くのアプリケーションにとってパフォーマンスは十分以上です。
もちろん、実稼働環境で Rails アプリケーションを実行する場合は、ユーザーが遭遇する可能性のある問題を監視する必要があります。 Action Cable のコンシューマとチャネルに問題が発生したとき、 ユーザーが発生する前に知りたいと思いませんか? ?
Honeybadger は、リアルタイム アプリケーションのデプロイに重要な Rails エラーとパフォーマンスの監視に最適な選択肢です。 Honeybadger は、アプリケーションのどこか (バックエンドとクライアント側) でエラーが発生すると即座に警告を発し、アプリケーションのログとパフォーマンス データを取得して、迅速な検索、トラブルシューティング、解決を行います。
Honeybadger に登録して始めましょう!
-
Rails セキュリティのベスト プラクティスに関する包括的なガイド
あなたも私と同じなら、素晴らしいアプリを構築するのが好きでこのビジネスに参入したはずです。開発分野に十分長く携わっていれば、 最終的にはそれほど素晴らしいと感じられないような素晴らしいアプリの作業をしなければならないことになります。 。セキュリティもその 1 つです。 Rails フレームワークが面倒な作業の多くを行っているとしても、Rails のセキュリティを真剣に考えることは重要です。 Ruby on Rails のセキュリティの詳細に深く入る前に、少し時間を取って、良き時代を振り返ってみましょう。 ...そして現実世界に戻ります。 セキュリティの脅威について心配しなければならな
-
Rubyの実用的なリンクリスト
これは、「Rubyの実用的なコンピュータサイエンス」シリーズの3番目のエントリです。今日はリンクリストについてお話します。 では、リンクリストとは何ですか? 名前が示すように、リンクリストはデータをリスト形式で保存する方法です(ありがとう、キャプテンオブビシャス!)。 「リンクされた」部分は、データがノードに格納され、これらのノードが順番に相互にリンクされているという事実に由来します。 これはアレイとどう違うのですか? リンクリストと配列 リンクリストには、配列とは異なるパフォーマンス特性があります。これが、どちらかを選択する理由の1つです。 これは、リンクリストが配列よりも