【Rails】Action Cableについて


Action Cableが誕生した背景

ユーザーの入力なしに、最新の情報をWebに表示する「Realtime性」をもつリッチな体験を実現するために誕生しました。

Action Cableは、RailsのRESTとWebSocketのシームレスな統合です。
例えばAction Cableを使うことで、みなさんが使っているようなリアルタイムチャットアプリを
作成することもできます。

用語について

Websocket

・Web上でクライアント、サーバ間の双方向通信を実現するための通信規格
・送信できるデータはテキストまたはバイナリ
・HTTPとは別のプロトコルなのでCookieは送られない
・通信が確立した後はクライアント、サーバーどちらからでもメッセージを送ることが可能

Connection

・Websocketとしてのコネクションを表すクラス
・Websocketとして通信が確立した時点でインスタンスが生成される
・開始時のリクエストはふつうのHTTPなのでCookieも送られる
・認証処理はこのクラス内に記述

Consumer

・Websocketコネクションのクライアント(ブラウザなど)
・同じブラウザの異なるタブは完全に別のクライアントとして扱う

サーバー側(Rails)の構成要素

Conection

コネクションは、ApplicationCable::Connectionのインスタンスです。
このクラスでは、受信したコネクションを承認し、ユーザーを特定できた場合にコネクションを確立します。
そのための仕組みとして、identified_byを使います。
identified_byはコネクションIDであり、後で特定のコネクションを見つけるときに利用できます。

# 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
        if verified_user = User.find_by(id: cookies.encrypted[:user_id])
          verified_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

Channel

チャネルはMVCでいうコントローラーの役割を担います。

Subscription

コンシューマーは、チャネルを購読するサブスクライバ側(Subscriber)の役割を果たします。
そして、コンシューマーのコネクションはサブスクリプション(Subscription: 購読)と呼ばれます。

# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  # コンシューマーがこのチャネルのサブスクライバ側になると
  # このコードが呼び出される
  def subscribed
  end
end

例1. ユーザーアピアランスの表示

これはユーザーがオンラインかどうかという情報を追跡するチャネルの例が以下です(オンラインユーザーの横に緑の点を表示する機能を作成する場合などに便利)。

まずは、サーバー側のアピアランスチャンネルを作成します。

# app/channels/appearance_channel.rb
class AppearanceChannel < ApplicationCable::Channel
  def subscribed
    current_user.appear
  end

  def unsubscribed
    current_user.disappear
  end

  def appear(data)
    current_user.appear(on: data['appearing_on'])
  end

  def away
    current_user.away
  end
end

サブスクリプションが開始されると、subscribedコールバックがトリガーされ、
そのユーザーがオンラインであることを示します。

例2. 新しいWeb通知を受信する

Websocketコネクションを使って、サーバーからクライアント側の機能をリモート実行させます。

このWeb通知チャネルは、正しいストリームにブロードキャストを行ったときに、クライアント側でWeb通知を表示します。

サーバー側のWeb通知チャネルは以下です。

# app/channels/web_notifications_channel.rb
class WebNotificationsChannel < ApplicationCable::Channel
  def subscribed
    stream_for current_user
  end
end

アプリケーションのどこからでも、web通知チャネルのインスタンスにコンテンツをブロードキャストできます。

# このコードはアプリケーションのどこか(NewCommentJob あたり)で呼び出される
WebNotificationsChannel.broadcast_to(
  current_user,
  title: 'New things!',
  body: 'All the news fit to print'
)

参考

Railsガイド
描いて理解する Action Cable