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