# Action CableとWebSocket完全ガイド:2026年Ruby on Rails技術面接対策 > Ruby on RailsのAction CableとWebSocketの深掘り解説。コネクション、チャンネル、ブロードキャスト、Rails 8のSolid Cable、Redisによるスケーリング、テスト手法まで面接で問われるポイントをコード例とともに網羅します。 - Published: 2026-05-07 - Updated: 2026-05-07 - Author: Anthony Fillion-Maillet - Tags: ruby on rails, action cable, websockets, real-time, solid cable, rails 8 - Reading time: 12 min --- Action Cableは、WebSocketサポートをRailsフレームワークに直接統合する仕組みであり、チャット、通知、ライブダッシュボードなどのリアルタイム機能を外部依存なしに実現できます。2026年の技術面接では、Action Cableの内部構造――コネクションのライフサイクルから本番環境でのスケーリングまで――を深く理解しているかどうかが、候補者の実力を見極める重要な判断基準となっています。 > **面接での重要ポイント** > > Action Cableは、コントローラやモデルと同じRailsの規約に従ってWebSocketを統合します。Rails 8で導入されたSolid Cableは、データベースベースのアダプターにより、pub/subメッセージングにおけるRedis依存を排除します。 ## WebSocketプロトコルの基礎とRailsにおける位置づけ WebSocketプロトコル(RFC 6455)は、単一のTCP接続上で永続的な全二重通信チャンネルを確立します。HTTPのリクエスト・レスポンスサイクルとは異なり、WebSocketは接続を維持し続け、クライアントとサーバーの双方がいつでもメッセージを送信できます。 Action Cableは、このプロトコルをRailsに馴染みやすい抽象化で包み込みます。サーバーは`/cable`でWebSocketのアップグレードを処理し、コネクション認証を管理し、チャンネルを通じてメッセージをルーティングします。クライアントサイドのJavaScriptライブラリが、サブスクリプションの作成と管理を自動的に行います。 一般的なHTTPリクエストはミリ秒単位で完了して閉じられますが、WebSocket接続は数分、数時間、あるいはセッション全体にわたって維持されます。この根本的な違いが、Action Cableにおけるすべてのアーキテクチャ上の判断を左右します。 ## Action Cableアーキテクチャ:コネクション、チャンネル、サブスクリプション Action Cableは、3つのコア抽象化によるレイヤードアーキテクチャに従います。コネクションは認証を処理し、チャンネルはビジネスロジックをカプセル化し、サブスクリプションはコンシューマーと特定のチャンネルを結びつけます。 ```ruby # app/channels/application_cable/connection.rb module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user def connect self.current_user = find_verified_user end private def find_verified_user # Cookies are available in WebSocket handshake if verified_user = User.find_by(id: cookies.encrypted[:user_id]) verified_user else reject_unauthorized_connection end end end end ``` コネクションクラスは、WebSocketハンドシェイクごとに1回実行されます。認証はここで行われ、個々のチャンネルでは行いません。`identified_by`宣言はユーザーIDを登録し、その接続上のすべてのチャンネルサブスクリプションで利用可能にします。 ```ruby # app/channels/chat_channel.rb class ChatChannel < ApplicationCable::Channel def subscribed room = ChatRoom.find(params[:room_id]) # Authorization: verify user belongs to this room if room.members.include?(current_user) stream_for room else reject end end def receive(data) message = ChatMessage.create!( room_id: params[:room_id], user: current_user, body: data["body"] ) ChatChannel.broadcast_to( message.room, { id: message.id, body: message.body, user: current_user.name } ) end def unsubscribed # Cleanup: mark user as offline AppearanceTracker.mark_offline(current_user) end end ``` チャンネルは3つのライフサイクルコールバックを定義します:`subscribed`、`receive`、`unsubscribed`。`stream_for`メソッドは、サブスクリプションを特定のモデルインスタンスにバインドし、名前空間付きのストリームを作成します。そのストリームへのブロードキャストは、接続しているすべてのサブスクライバーにメッセージを配信します。 ## クライアントサイドのJavaScriptサブスクリプション クライアントサイドのコンシューマーは、Action Cableサーバーに接続し、サブスクリプションを管理します。各サブスクリプションは、サーバーサイドのチャンネルに対応します。 ```javascript // app/javascript/channels/chat_channel.js import consumer from "./consumer" const chatChannel = consumer.subscriptions.create( { channel: "ChatChannel", room_id: roomId }, { connected() { // Called when the subscription is ready console.log("Connected to chat room", roomId) }, disconnected() { // Called when the subscription is closed console.log("Disconnected from chat room") }, received(data) { // Called when data is broadcast to the channel const messageList = document.getElementById("messages") messageList.insertAdjacentHTML("beforeend", `
` ) }, sendMessage(body) { // Calls ChatChannel#receive on the server this.perform("receive", { body: body }) } } ) ``` `received`コールバックは、サーバーがサブスクライブ中のストリームにブロードキャストするたびに発火します。`perform`メソッドは、クライアントからサーバーへデータを送信し、対応するチャンネルメソッドを呼び出します。 ## Rails 8のSolid Cable:データベースベースのPub/Sub Rails 8では、Solid QueueやSolid Cacheと並ぶ「Solid三部作」の一つとして、Solid Cableが導入されました。Solid Cableは、メッセージをデータベーステーブルに保存することで、pub/subバックエンドとしてのRedisを置き換えます。 ```yaml # config/cable.yml (Rails 8 default) development: adapter: solid_cable production: adapter: solid_cable connects_to: database: writing: cable polling_interval: 0.1.seconds message_retention: 1.day ``` Solid Cableは、各ブロードキャストメッセージをデータベーステーブルに書き込み、設定可能な間隔で新しいメッセージをポーリングする仕組みで動作します。デフォルトのポーリング間隔100msは、ほとんどのアプリケーションでほぼリアルタイムの配信を実現します。 トレードオフは明確です。Solid Cableはインフラストラクチャ依存(Redis)を排除する代わりに、若干高いレイテンシーとデータベース負荷が発生します。すでにPostgreSQLやMySQLを運用しているアプリケーションでは、このトレードオフが適切な選択となることが多いです。1秒あたり数千メッセージの高頻度ブロードキャストでは、依然としてRedisの方が適しています。 ```ruby # config/database.yml (Rails 8 multi-database) production: primary: <<: *default database: myapp_production cable: <<: *default database: myapp_cable_production migrations_paths: db/cable_migrate ``` Solid Cableは専用データベースを使用して、プライマリデータベースとの競合を回避します。この分離により、メッセージポーリングがアプリケーションクエリに干渉することを防ぎます。 ## ブロードキャストパターンとサーバーサイドトリガー モデル、ジョブ、コントローラからのブロードキャストは、本番Railsアプリケーションで最も一般的な3つのパターンをカバーします。 ```ruby # Broadcasting from a model callback class Notification < ApplicationRecord belongs_to :user after_create_commit :broadcast_to_user private def broadcast_to_user ActionCable.server.broadcast( "notifications_#{user_id}", { id: id, title: title, read: false } ) end end # Broadcasting from a background job class DashboardUpdateJob < ApplicationJob queue_as :default def perform(dashboard_id) dashboard = Dashboard.find(dashboard_id) stats = dashboard.compute_stats ActionCable.server.broadcast( "dashboard_#{dashboard_id}", { stats: stats, updated_at: Time.current.iso8601 } ) end end ``` モデルコールバックは、レコード変更によってトリガーされるシンプルな通知に適しています。バックグラウンドジョブは、ダッシュボード統計の計算やデータ集約など、より重い処理をリクエストサイクルをブロックせずに処理します。ブロードキャスト自体は常に軽量で、ペイロードをシリアライズしてアダプターにパブリッシュするだけです。 ## Turbo StreamsとAction Cableの統合 Rails 8のHotwireは、Action CableをTurbo Streamsのトランスポートレイヤーとして使用し、カスタムJavaScriptを書くことなくリアルタイムのDOM更新を実現します。 ```ruby # app/models/message.rb class Message < ApplicationRecord belongs_to :chat_room # Automatically broadcasts append to subscribers broadcasts_to :chat_room end # app/views/chat_rooms/show.html.erb <%= turbo_stream_from @chat_room %>