Action Cable Compatibility

This compatibility table shows which Action Cable features are supported by AnyCable Rails.

Feature Status
Connection identifiers ✅*
Connection request data (cookies, params)
Disconnect handling
Subscribe to channels
Parameterized subscriptions
Unsubscribe from channels
Subscription Instance Variables ✅ **
Performing Channel Actions
Streaming
Custom stream callbacks 🚫
Broadcasting
Periodical timers 🚫
Disconnect remote clients
Command callbacks ✅ ***

* See restoring state objects for more information on how identifiers work.

** See channel state for more information on subscription instance variables support.

*** AnyCable (via anycable-rails) also supports command callbacks (before_command, after_command, around_command) for older Rails versions (event when not using AnyCable).

Runtime checks

AnyCable Rails provides a way to enforce compatibility through runtime checks.

Runtime checks are monkey-patches which raise exceptions (AnyCable::CompatibilityError) when AnyCable-incompatible code is called.

To enabled runtime checks add the following file to your configuration (e.g. config/<env>.rb or config/initializers/anycable.rb):

require "anycable/rails/compatibility"

NOTE: compatibility checks could be used with Action Cable (i.e. w/o AnyCable) and don't affect compatible functionality; thus it makes sense to add runtime checks in development and test environments.

For example, the following channel class:

class ChatChannel < ApplicationCable::Channel
  def subscribed
    @room = ChatRoom.find(params[:id])
  end
end

raises AnyCable::CompatibilityError when client tries to subscribe to the channel, 'cause AnyCable doesn't support storing channel's state in instance variables.

RuboCop cops

AnyCable Rails comes with RuboCop rules to detect incompatible code in your application.

Add to your .rubocop.yml:

require:
  - "anycable/rails/rubocop"
# ...

And run rubocop:

$ bundle exec rubocop

#=> app/channels/bad_channel.rb:5:5: C: AnyCable/InstanceVars: Channel instance variables are not supported in AnyCable. Use state_attr_accessor instead.
#=>    @bad_var = "bad"
#=>    ^^^^^^^^^^^^^^^^

Or you can require AnyCable Rails cops dynamically:

bundle exec rubocop -r 'anycable/rails/rubocop' --only AnyCable

NOTE: If you have DisabledByDefault: true in your RuboCop config, you need to specify all AnyCable Rails cops explicitly:

bundle exec rubocop -r 'anycable/rails/rubocop' \
--only AnyCable/InstanceVars,AnyCable/PeriodicalTimers,AnyCable/InstanceVars

You can also install AnyCable Rails RuboCop extension as a separate gem (for example, if you use a dedicated RuboCop Gemfile):

gem "rubocop-anycable-rails"

Cops

AnyCable/InstanceVars

Checks for instance variable usage inside channels:

# bad
class MyChannel < ApplicationCable::Channel
  def subscribed
    @post = Post.find(params[:id])
    stream_from @post
  end
end

# good
class MyChannel < ApplicationCable::Channel
  def subscribed
    post = Post.find(params[:id])
    stream_from post
  end
end

AnyCable/StreamFrom

Checks for stream_from calls with custom callbacks or coders:

# bad
class MyChannel < ApplicationCable::Channel
  def follow
    stream_from("all") {}
  end
end

class MyChannel < ApplicationCable::Channel
  def follow
    stream_from("all", -> {})
  end
end

class MyChannel < ApplicationCable::Channel
  def follow
    stream_from("all", coder: SomeCoder)
  end
end

# good
class MyChannel < ApplicationCable::Channel
  def follow
    stream_from "all"
  end
end

AnyCable/PeriodicalTimers

Checks for periodical timers usage:

# bad
class MyChannel < ApplicationCable::Channel
  periodically(:do_something, every: 2.seconds)
end