51
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

描いて理解する Action Cable

Posted at

はじめに

コロナ騒ぎで時間があるので Rails の Action Cable を触ってみました。

基本的な使い方は Rails ガイドで調べましたが、いまいちピンとこなかったので理解するために図を描きました。特に用語についての章を読んでもそれぞれの用語の関係性がよく分からなかったので、自分なりに整理しています。

用語について

Connection, Consumer

ActionCable-Connection.png

WebSocket の基礎

  • Web 上でクライアント、サーバ間の双方向通信を実現するための通信規格
  • Upgrade: websocket ヘッダをつけた HTTP リクエストで開始
  • レスポンスとして HTTP ステータス 101(Switching Protocols) が返ってきたら TCP コネクションを使いまわして WebSocket として通信ができる
  • 送信できるデータはテキストまたはバイナリ
  • HTTP とは別のプロトコルなので Cookie などは送られない
  • 通信が確立したあとはクライアント、サーバどちらからでもメッセージを送ることが可能

Connection

  • WebSocket としてのコネクションを表すクラス
  • (おそらく)WebSocket として通信が確立した時点でインスタンスが生成される
  • 開始時のリクエストはふつうの HTTP なので Cookie も送られる
  • なので connection.rb では cookies が使える
  • 認証処理はこのクラス内に記述

Consumer

  • WebSocket コネクションのクライアント(ブラウザなど)
  • HTTP とは異なり、同じブラウザの異なるタブは完全に別のクライアントとして扱われる

Consumer を区別する方法

HTTP とは異なり毎回認証情報が送られたりはしないので、コネクション確立時に「このコネクションは誰のものか」をサーバー側で管理する必要がある。

そのためのしくみとして Action Cable では Connection クラスの identified_by を使う。

# app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user
 
    def connect
      self.current_user = User.find_by(id: cookies.encrypted[:user_id])
    end
 
  end
end

Channel, Subscription

ActionCable-Subscription.png

Channel

  • 文字通りのチャンネル
  • Controller のようなもの

Subscription

  • チャネルの購読
  • ひとつのコネクション内でいくつでも作成可能
  • あるチャネルの購読をしている、という意味ではコンシューマをサブスクライバとも呼ぶ

以下のように consumer.subscriptions.create で新たな Subscription オブジェクトが作成され、consumer.subscriptions に追加される。

chat_channel.js
import consumer from "./consumer"
consumer.subscriptions.create("ChatChannel", {
  // 略
});

Stream

ActionCable-Stream.png

  • ブロードキャストを行う場合に使う
  • チャネルがサブスクリプションとストリームの紐付けを行う
  • あるストリームにブロードキャストした場合、そのストリームに紐づくサブスクリプションにメッセージが送られる

たとえば以下のようなチャネルクラスを定義しておくと ChatChannel をサブスクライブしたときに chat_001 というストリームに紐付けられる。

chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_001"
  end
end

この状態で以下のコードが実行されると、サブスクライバに {"text": "Hello, World!"} というJSON文字列が送られる。

broadcast
data = {text: "Hello, World!"}
ActionCable.server.broadcast("chat_001", data)

ストリームに対するブロードキャスト自体は、Rails アプリケーションのどこからでも実行可能。

複数のStream

ActionCable-Stream-2.png

前節の例では固定文字列だったので、どのサブスクリプションも同じストリームに紐付いていました。しかし、チャネルをサブスクライブするときサーバー側にパラメータを渡すことができるので、ユーザーごと、もしくは開いているページごとに異なるストリームに紐付けることが可能です。

まとめ

ActionCable-まとめ.png

ストリームとサブスクリプションの関係がよく分からなかったのでそこを中心に図示してみました。この図だとストリームが必須みたいに見えてしまうので、action パラメータによってサーバー側のメソッドを実行する、という観点でも整理して別途記事にしてみようと思います。

51
45
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?