# 機能設計書 12-Action Cable

## 概要

本ドキュメントは、Ruby on RailsフレームワークにおけるWebSocketフレームワーク「Action Cable」の機能設計を記載する。Action Cableは単一のWebSocket接続上で多数のリアルタイム機能をチャンネルとして構造化し、クライアントとサーバー間の双方向通信を実現する。

### 本機能の処理概要

Action Cableは、WebSocket通信を用いたリアルタイム双方向通信フレームワークである。サーバーからクライアントへのプッシュ通知、チャットアプリケーション、ライブ更新など、リアルタイム性が求められる機能を実装するための基盤を提供する。

**業務上の目的・背景**：
従来のHTTPリクエスト/レスポンスモデルでは、サーバーからクライアントへの即座のデータプッシュが困難である。ポーリングを使用すると、遅延が生じるとともにサーバーリソースを無駄に消費する。Action Cableは、WebSocketプロトコルを使用して永続的な双方向接続を確立し、サーバーサイドの状態変化をクライアントにリアルタイムで通知することで、ユーザー体験を向上させる。また、Railsの規約に沿った設計により、複雑なWebSocket処理を簡潔に実装できる。

**機能の利用シーン**：
- リアルタイムチャットアプリケーション
- ライブ通知システム（新着メッセージ、アラート等）
- リアルタイムダッシュボード・モニタリング
- コラボレーティブ編集（共同編集ドキュメント等）
- ゲームのリアルタイム更新
- 在席状況（プレゼンス）の表示

**主要な処理内容**：
1. WebSocket接続の確立と認証
2. チャンネルへのサブスクリプション管理
3. クライアントからのアクション呼び出し
4. サーバーからクライアントへのブロードキャスト
5. Pub/Subアダプタによるスケールアウト対応
6. コネクション識別子による接続管理
7. ストリーム機能によるデータ配信

**関連システム・外部連携**：
- Redis（Pub/Subアダプタとして使用）
- PostgreSQL（Pub/Subアダプタとして使用可能）
- Active Record（コネクション識別子としてユーザーモデル等を使用）
- Turbo Streams（Action CableをトランスポートとしてDOM更新）

**権限による制御**：
- コネクション確立時に認証・認可を実施（`connect`メソッド）
- チャンネルサブスクリプション時に権限チェック（`subscribed`メソッドで`reject`可能）
- 不正な接続は`reject_unauthorized_connection`で拒否

## 関連画面

本機能はバックエンド通信基盤のため、直接関連する画面はない。ただし、多くの画面でWebSocket通信の基盤として使用される。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

リアルタイム通信 / WebSocket / Pub/Sub

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| identifier | String(JSON) | Yes | チャンネル識別子とパラメータ | JSON形式 |
| command | String | Yes | コマンド種別（subscribe/unsubscribe/message） | 定義済みコマンドのみ |
| data | String(JSON) | No | アクションに渡すデータ | JSON形式 |
| action | String | No | 呼び出すチャンネルアクション名 | チャンネルのパブリックメソッド |

### 入力データソース

- WebSocketメッセージ（クライアントJavaScript）
- Cookieセッション（認証情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| type | String | メッセージタイプ（welcome/ping/confirm_subscription/reject_subscription等） |
| identifier | String | チャンネル識別子 |
| message | Object | 配信データ |
| reason | String | 切断理由（disconnect時） |
| reconnect | Boolean | 再接続フラグ |

### 出力先

- WebSocketコネクション（クライアントへの送信）
- Pub/Subアダプタ（ブロードキャスト時）

## 処理フロー

### 処理シーケンス

```
1. WebSocket接続確立
   └─ ActionCable::Connection::Base#process
      └─ 認証処理（connectメソッド）
      └─ ウェルカムメッセージ送信

2. チャンネルサブスクリプション
   └─ ActionCable::Connection::Subscriptions#add
      └─ チャンネルインスタンス生成
      └─ subscribedコールバック実行
      └─ 確認/拒否メッセージ送信

3. アクション実行
   └─ ActionCable::Channel::Base#perform_action
      └─ アクションメソッド呼び出し
      └─ transmitでクライアントへ送信

4. ブロードキャスト
   └─ ActionCable.server.broadcast
      └─ Pub/Subアダプタ経由で配信
      └─ サブスクライバーにメッセージ送信
```

### フローチャート

```mermaid
flowchart TD
    A[クライアント接続] --> B[WebSocket ハンドシェイク]
    B --> C{接続許可?}
    C -->|No| D[接続拒否]
    C -->|Yes| E[connect callback]
    E --> F[ウェルカムメッセージ送信]
    F --> G[メッセージ待機]
    G --> H{コマンド種別}
    H -->|subscribe| I[チャンネル生成]
    I --> J{subscribed callback}
    J -->|reject| K[サブスクリプション拒否]
    J -->|accept| L[サブスクリプション確認]
    L --> M[ストリーム設定]
    M --> G
    H -->|message| N[アクション実行]
    N --> O[perform_action]
    O --> G
    H -->|unsubscribe| P[チャンネル破棄]
    P --> Q[unsubscribed callback]
    Q --> G
    G --> R{接続終了?}
    R -->|Yes| S[disconnect callback]
    S --> T[クリーンアップ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 同一オリジンチェック | デフォルトでCSRF保護のため同一オリジンからの接続のみ許可 | 常時 |
| BR-002 | 識別子の一意性 | コネクション識別子はアプリケーション全体で一意 | 常時 |
| BR-003 | チャンネルインスタンスの永続性 | チャンネルインスタンスは接続中保持される | サブスクリプション中 |
| BR-004 | ストリーム名の規約 | ストリーム名はブロードキャストチャンネルを一意に識別 | stream_from使用時 |

### 計算ロジック

特になし

## データベース操作仕様

Action Cable自体はデータベースを直接操作しない。ただし、PostgreSQL Pub/Subアダプタ使用時はNOTIFY/LISTENを利用する。

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | アダプタ依存 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UnauthorizedError | 例外 | 認証失敗時 | 接続を拒否、再接続不可で切断 |
| WebSocketError | 例外 | WebSocket通信エラー | エラーログ出力 |
| - | サブスクリプション拒否 | reject呼び出し時 | クライアントに拒否通知 |

### リトライ仕様

- クライアント側で自動再接続を実装（ActionCable.js）
- サーバー側は再接続時に新規接続として処理

## トランザクション仕様

- WebSocket通信はHTTPとは独立
- チャンネル内でのActive Record操作は通常のトランザクションが適用

## パフォーマンス要件

- WebSocket接続は永続的なためメモリ消費に注意
- 大量の同時接続にはRedis Pub/Subの使用を推奨
- ブロードキャスト時の負荷分散にはadapter poolingを検討

## セキュリティ考慮事項

- WebSocket接続時にセッションCookieによる認証
- `identified_by`で宣言した識別子による接続管理
- `reject_unauthorized_connection`による不正接続の拒否
- 同一オリジンポリシーの適用（`allowed_request_origins`で設定可能）
- XSS脆弱性対策としてメッセージ内容のサニタイズ

## 備考

- Action CableはRails 5.0で導入された
- 本番環境ではRedis Pub/Subアダプタの使用を推奨
- Rack hijacking APIを使用してWebSocket接続を処理

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

接続とチャンネルの基本構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | internal.rb | `actioncable/lib/action_cable.rb` | INTERNAL定数（メッセージタイプ定義） |
| 1-2 | identification.rb | `actioncable/lib/action_cable/connection/identification.rb` | identified_byによる識別子定義 |

**読解のコツ**: INTERNAL定数でWebSocketメッセージのプロトコルを定義している。message_typesやdisconnect_reasonsを確認する。

#### Step 2: コネクション処理を理解する

WebSocket接続の確立と管理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | base.rb | `actioncable/lib/action_cable/connection/base.rb` | Connection::Baseクラスの構成、process/receive/transmit |

**主要処理フロー**:
- **68-80行目**: initializeでWebSocket、Subscriptions、MessageBufferを初期化
- **86-94行目**: processメソッドでWebSocket接続の検証と開始
- **98-108行目**: receiveとdispatch_websocket_messageでメッセージ処理
- **202-212行目**: handle_openでconnectコールバック呼び出し

#### Step 3: チャンネル処理を理解する

チャンネルのサブスクリプションとアクション実行を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | base.rb | `actioncable/lib/action_cable/channel/base.rb` | Channel::Baseクラス、perform_action/subscribed/transmit |

**主要処理フロー**:
- **163-179行目**: initializeでコネクション参照、パラメータ設定
- **184-195行目**: perform_actionでアクション抽出と実行
- **199-206行目**: subscribe_to_channelでサブスクリプション処理
- **239-250行目**: transmitでクライアントへのデータ送信

#### Step 4: ストリーミングとブロードキャストを理解する

リアルタイムデータ配信の仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | streams.rb | `actioncable/lib/action_cable/channel/streams.rb` | stream_from/stream_for |
| 4-2 | broadcasting.rb | `actioncable/lib/action_cable/server/broadcasting.rb` | broadcastメソッド |

#### Step 5: Pub/Subアダプタを理解する

スケールアウトのためのアダプタ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | base.rb | `actioncable/lib/action_cable/subscription_adapter/base.rb` | アダプタのインターフェース |
| 5-2 | redis.rb | `actioncable/lib/action_cable/subscription_adapter/redis.rb` | Redisアダプタ実装 |

### プログラム呼び出し階層図

```
WebSocket接続要求
    │
    └─ ActionCable::Server::Base#call (Rack app)
           │
           └─ ActionCable::Connection::Base#process
                  │
                  ├─ allow_request_origin? (CSRF検証)
                  │
                  └─ respond_to_successful_request
                         │
                         └─ websocket.rack_response
                                │
                                └─ on_open (非同期)
                                       │
                                       ├─ connect callback
                                       │
                                       └─ send_welcome_message
                                              │
                                              └─ メッセージ受信待機

WebSocketメッセージ受信
    │
    └─ ActionCable::Connection::Base#receive
           │
           └─ dispatch_websocket_message
                  │
                  └─ handle_channel_command
                         │
                         └─ ActionCable::Connection::Subscriptions#execute_command
                                │
                                ├─ subscribe
                                │      │
                                │      └─ ActionCable::Channel::Base#subscribe_to_channel
                                │             │
                                │             ├─ subscribed callback
                                │             │
                                │             └─ stream_from / stream_for
                                │
                                ├─ unsubscribe
                                │      │
                                │      └─ unsubscribe_from_channel
                                │
                                └─ perform_action
                                       │
                                       └─ ActionCable::Channel::Base#perform_action
                                              │
                                              └─ dispatch_action
                                                     │
                                                     └─ public_send(action, data)
```

### データフロー図

```
[入力]                           [処理]                          [出力]

クライアントJS ───────▶ WebSocket接続 ─────────▶ Connection::Base
                                                      │
                           ┌──────────────────────────┘
                           │
                           ▼
                    Subscriptions ───▶ Channel::Base
                           │                 │
                           │                 ├─▶ subscribed
                           │                 │
                           │                 └─▶ stream_from
                           │                          │
                           │                          ▼
                           │                  SubscriptionAdapter
                           │                          │
                           │                          ▼
                           │                    Redis/PostgreSQL
                           │
                           │
Server.broadcast ─────────────────────────▶ SubscriptionAdapter
                                                      │
                                                      ▼
                                             Channel#transmit
                                                      │
                                                      ▼
                                             WebSocket送信 ─────▶ クライアントJS
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| action_cable.rb | `actioncable/lib/action_cable.rb` | ソース | モジュール定義、INTERNAL定数 |
| base.rb | `actioncable/lib/action_cable/connection/base.rb` | ソース | WebSocket接続管理 |
| identification.rb | `actioncable/lib/action_cable/connection/identification.rb` | ソース | 接続識別子定義 |
| authorization.rb | `actioncable/lib/action_cable/connection/authorization.rb` | ソース | 認可ヘルパー |
| subscriptions.rb | `actioncable/lib/action_cable/connection/subscriptions.rb` | ソース | サブスクリプション管理 |
| web_socket.rb | `actioncable/lib/action_cable/connection/web_socket.rb` | ソース | WebSocket抽象化 |
| message_buffer.rb | `actioncable/lib/action_cable/connection/message_buffer.rb` | ソース | メッセージバッファリング |
| base.rb | `actioncable/lib/action_cable/channel/base.rb` | ソース | チャンネル基底クラス |
| streams.rb | `actioncable/lib/action_cable/channel/streams.rb` | ソース | ストリーム機能 |
| broadcasting.rb | `actioncable/lib/action_cable/channel/broadcasting.rb` | ソース | ブロードキャスト機能 |
| callbacks.rb | `actioncable/lib/action_cable/channel/callbacks.rb` | ソース | チャンネルコールバック |
| periodic_timers.rb | `actioncable/lib/action_cable/channel/periodic_timers.rb` | ソース | 定期実行タイマー |
| base.rb | `actioncable/lib/action_cable/server/base.rb` | ソース | サーバー本体 |
| broadcasting.rb | `actioncable/lib/action_cable/server/broadcasting.rb` | ソース | サーバーブロードキャスト |
| configuration.rb | `actioncable/lib/action_cable/server/configuration.rb` | ソース | サーバー設定 |
| worker.rb | `actioncable/lib/action_cable/server/worker.rb` | ソース | ワーカープール |
| base.rb | `actioncable/lib/action_cable/subscription_adapter/base.rb` | ソース | アダプタ基底クラス |
| redis.rb | `actioncable/lib/action_cable/subscription_adapter/redis.rb` | ソース | Redisアダプタ |
| postgresql.rb | `actioncable/lib/action_cable/subscription_adapter/postgresql.rb` | ソース | PostgreSQLアダプタ |
| async.rb | `actioncable/lib/action_cable/subscription_adapter/async.rb` | ソース | 非同期アダプタ |
| remote_connections.rb | `actioncable/lib/action_cable/remote_connections.rb` | ソース | リモート接続切断 |
| engine.rb | `actioncable/lib/action_cable/engine.rb` | ソース | Rails Engine統合 |
