Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
7
Help us understand the problem. What is going on with this article?
@suzuki-r

Action Cableについて調べたことまとめ

More than 1 year has passed since last update.

最近プロジェクトで、Action Cableを使う機会があり、いろいろ調べたので、備忘のため書いておこうと思います。
(そして、Qiita初投稿イェイ!!)

Ruby:2.4.1
Rails:5.1.2

はじめに

Action Cableって何?

  • WebSocketとRailsのその他の部分をシームレスに統合したもの

  • 一度、HTTPのコネクションが確立すると、websocket通信で、サーバー・クライアントの両方からリクエストが遅れる状態を簡単に実装できちゃいます。

てな感じです。

サーバー側のコンポーネント

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

    protected
      def find_verified_user
        if current_user = User.find_by(id: cookies.signed[:user_id])
          current_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

クライアントとサーバー側の関係を確立させる基礎が上で確立されます。
同時に、current_userが初期状態では使えませんでしたが、これで使えるようになります。
deviseを使用されている方のため、current_#{model名}の依存はないので、ご安心を・・・

ここで、ユーザーが特定できた時点で、コネクションが確立します。

クライアント側のコンポーネント

メッセージ送信はこちらを参考にしてください。

app/assets/javascripts/channels/comments.coffee
  connected: ->
    # FIXME: While we wait for cable subscriptions to always be finalized before sending messages
    setTimeout =>
      @followCurrentMessage()
    , 1000

    followCurrentMessage: ->
      # channel購読の条件

connectedで、購読するchannelを定義します。
デフォルトでは、何も書かれていない状態になるので、connection.rbで接続が確立した時点で、
channelのコンシューマーになります。

特定のページで、channel購読をする(例えば、メッセージ画面でのみしたい)であれば、
templateに任意のパラメーターを設定して、jsで取得し、条件を追記してみてもいいかもです。

app/assets/javascripts/channels/comments.coffee
    # 省略

    followCurrentMessage: ->
      if messageId = $("#message-list").data('message-id')
        @perform 'follow', message_id: messageId
      else
        @perform 'unfollow'

ここでは、templateでdata-message-id="XX"を取得して、代入できれば、
channel購読ができるようになっています。

サーバー・クライアント間のやりとり

クライアント側

app/assets/javascripts/channels/comments.coffee
    # 省略

    followCurrentMessage: ->
      if messageId = $("#message-list").data('message-id')
        @perform 'follow', message_id: messageId
      else
        @perform 'unfollow'

サーバー側

channels/XXXX.coffeeで定義したメソッドをここで指定します

actioncable-examples/app/channels/comments_channel.rb
class CommentsChannel < ApplicationCable::Channel
  def follow(data)
    stop_all_streams
    stream_from "messages:#{data['message_id'].to_i}:comments"
  end

  def unfollow
    stop_all_streams
  end
end

stream_fromに注目です。ここで、任意のchannelが設定できます。
followメソッドもクライアント側で設定した引数をつかって、サーバーサイドで利用できます。

app/jobs/comment_relay_job.rb
class CommentRelayJob < ApplicationJob
  def perform(comment)
    ActionCable.server.broadcast "messages:#{comment.message_id}:comments",
      comment: CommentsController.render(partial: 'comments/comment', locals: { comment: comment })
  end
end

設定されたコメントを指定のチャンネルを購読しているユーザーにブロードキャストをすれば、完成です。
modelに以下のコードを追加すれば、createされたコメントがブロードキャストされます。

app/models/comments.rb
  after_commit { CommentRelayJob.perform_later(self) }

インフラ的な要素であったり、railsの仕様がうまく理解できてませんが、上記で問題ないと思います。

以上です。
参考サイト:
Rails Guide
actioncable-example

7
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
suzuki-r
Railsをメインで書いてまーす!

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
7
Help us understand the problem. What is going on with this article?