Articles tagged with Action Cable

  1. Rails
    03 Jul 2016
    1. I just updated our Video Streaming App to Rails 5 and am very pleased with it.
      The upgrade path had just a minor bump with some failing test cases due to an incompatibility with devise 4.1.1 and therefore switched to 4.2.0 which was released 4 hours ago.

      Action Cable now finally works like a charm, no need to manage the AR Connections manually anymore and also the bug with deadlocks when using multiple channels is gone.

      Thinking back to the early days of Action Cable, it has come a long way and gives you an easy option to harness the power of websockets from within your Rails App.

      Some years ago I was quite intrigued by the websocket support of Torquebox 3 and on paper it all seemed awesome. You get a nice abstraction layer using the STOMP protocol with Stilts and perfect integration with a Bridge for JMS with your backend messaging system HornetQ all out of the box on a JBoss AS. You would have everything nicely bundled in your rails monolith and just deloy it in Torquebox and you are done, compared to the alternatives at the time where you would deploy your rails app to Phusion Passenger and have to setup something seperate for websockets. In practice it was kind of a letdown, for example one issue I encountered was that it wasn’t really reliable, websockets would just close down and stuff like that.

      Now with Action Cable it just works™. In the mentioned application we have a chat, updates of the current viewer count of a stream, the list of logged in users that watch it, and status changes all funneled through Action Cable backed by Redis with no hickups whatsoever.

  2. Rails
    15 Feb 2016
    1. After upgrading an app to Rails 5.0.0.beta2 I started playing with Action Cable.
      In this post I want to show how to do authorization in Cable Channels.
      Whether you use CanCanCan, Pundit or whatever, first off you will have to authenticate the user, after that you can do your permission checks.

      How to do authentication is shown in the Action Cable Examples. Basically you are supposed to fetch the user_id from the cookie. The example shows how to check if the user is signed in and if not reject the websocket connection.
      If you need more granular checks, keep reading.

    2. To understand the following code you should first familiarize yourself with the basics of Action Cable, the Readme is a good start.

      The goal here is to identify logged in users and do permission checks per message. One could also check permissions during initiation of the connection or the subscription of a channel, the most granular option is to verify permissions for each message. This can be beneficial if multiple types of messages or messages regarding different resources which require distinct permissions are delivered from the same queue.
      Also imagine permissions change while a channel is subscribed, you would propably want to stop sending messages immediately if a user gets the permission to receive them revoked.

    3. In the ApplicationCable we define methods to get the user from the session and Cancancan’s Ability through which we can check permissions.

      module ApplicationCable
        class Connection < ActionCable::Connection::Base
          identified_by :current_user
      
          def connect
            self.current_user = find_verified_user
          end
      
          def session
            cookies.encrypted[Rails.application.config.session_options[:key]]
          end
      
          def ability
            @ability ||= Ability.new(current_user)
          end
      
          protected
          def find_verified_user
            User.find_by(id: session["user_id"])
          end
        end
      end

      We give Channel access to the session and the ability object. The current user is already accessable through current_user.

      module ApplicationCable
        class Channel < ActionCable::Channel::Base
          delegate :session, :ability, to: :connection
          # dont allow the clients to call those methods
          protected :session, :ability
        end
      end

      So far we setup everything we need to verify permissions in our own channels.
      So now we can use the ability object to deny subscription in general, or in this case to filter which messages are sent.

      Notice: Currently using ActiveRecord from inside a stream callback depletes the connection pool. I reported this issue under #23778: ActionCable can deplete AR’s connection pool. Therefore we have to ensure the connection is checked back into the pool ourselfs.

      class StreamUpdatesChannel < ApplicationCable::Channel
        def subscribed
          queue = "stream_updates:#{params[:stream_id]}"
          stream_from queue, -> (message) do
            ActiveRecord::Base.connection_pool.with_connection do
              if ability.can? :show, Stream.find(params[:stream_id])
                transmit ActiveSupport::JSON.decode(message), via: queue
              end
            end
          end
        end
      end