This app's one real channel isn't custom

Free preview 3 min to read

app/channels/ doesn't exist in this app. It isn't empty; find app/channels finds nothing at all. Yet the roadmap page refreshes live when an admin reorders a course, over a WebSocket, through an ActionCable channel. This lesson is about the channel that does it, and the app didn't write it.

turbo_stream_from, traced to a class

app/views/catalog/courses/index.html.erb has one line for this: <%= turbo_stream_from "catalog_roadmap" %>. The helper renders a subscription tag pointed at Turbo::StreamsChannel, a class that ships inside the turbo-rails gem:

class Turbo::StreamsChannel < ActionCable::Channel::Base
  extend Turbo::Streams::Broadcasts, Turbo::Streams::StreamName
  include Turbo::Streams::StreamName::ClassMethods

  def subscribed
    if stream_name = verified_stream_name_from_params
      stream_from stream_name
    else
      reject
    end
  end
end

That's four lines of logic, and each is a primitive this course covers: subscribed (lesson 5), verified_stream_name_from_params (lesson 3), stream_from (lesson 4) and reject (lesson 5). The app relies on all four every time that page loads, without a channel of its own.

The gem's doc comment is this course's syllabus

The same file's header comment shows how to build a custom channel instead:

# class CustomChannel < ActionCable::Channel::Base
#   extend Turbo::Streams::Broadcasts, Turbo::Streams::StreamName
#   include Turbo::Streams::StreamName::ClassMethods
#
#   def subscribed
#     if (stream_name = verified_stream_name_from_params).present? &&
#         subscription_allowed?
#       stream_from stream_name
#     else
#       reject
#     end
#   end
#
#   def subscription_allowed?
#     # ...
#   end
# end

ActionCable::Channel::Base is the parent class of every channel that runs in this app, which today means the one from the gem. Learning it means learning what Turbo::StreamsChannel already relies on, one layer below where the app's own code touches it.

What "no app/channels" means

Rails doesn't require an app to define any channels. The cable server is mounted regardless, and any channel class Rails can load, gem-provided or not, can be subscribed to. This app uses one: Turbo::StreamsChannel, loaded from turbo-rails when a subscription names it. Nothing in config/cable.yml or config/routes.rb names a channel. The wiring is: the helper renders a tag, the JavaScript subscribes, the channel class is resolved by name, and subscribed runs. The next six lessons walk that path with channels the app doesn't have yet, running each step instead of trusting a tutorial.

Key takeaways

  • app/channels/ doesn't exist in this app, so it has no custom channel.
  • The one channel the app runs, Turbo::StreamsChannel, ships in the turbo-rails gem and subclasses ActionCable::Channel::Base, the same base class a custom channel would use.
  • Its four-line subscribed method already uses the primitives this course covers: verified_stream_name_from_params, stream_from and reject. The gem's doc comment shows the custom-channel shape the app hasn't needed.
  • Nothing in the app's configuration names a channel; a channel is resolved by name when a subscription asks for it, like any other Ruby class.
Lesson 1 of 7 · free

Keep going with lesson 2

Connections have no identity here

What identified_by does, and why this app's empty identifiers set gives every connection the same identifier.

A free account also gives you the quizzes, your progress and notes, and the discussion.

Type to start searching...