Action Cable Compatibility
This compatibility table shows which Action Cable features supported by anycable
gem (AnyCable servers may not support some of the features supported by gem).
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 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 integrates with RuboCop to detect incompatible code in your application.
Add to your .rubocop.yml
:
require:
- "anycable/rails/compatibility/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 cops dynamically:
bundle exec rubocop -r 'anycable/rails/compatibility/rubocop' --only AnyCable
NOTE: If you have DisabledByDefault: true
in your RuboCop config, you need to specify all AnyCable cops explicitly:
bundle exec rubocop -r 'anycable/rails/compatibility/rubocop' \
--only AnyCable/InstanceVars,AnyCable/PeriodicalTimers,AnyCable/InstanceVars
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