Action Cable en WebSockets in Rails: Complete Gids voor Technische Sollicitatiegesprekken 2026

Diepgaande behandeling van Action Cable voor Rails-interviews. Verbindingen, channels, Solid Cable, Turbo Streams, schaling met Redis en testpatronen met codevoorbeelden.

Action Cable en WebSockets in Rails

Action Cable brengt WebSocket-ondersteuning rechtstreeks naar het Rails-framework, waardoor realtime functionaliteiten zoals chat, notificaties en live dashboards mogelijk worden zonder externe afhankelijkheden. Voor technische sollicitatiegesprekken in 2026 is het begrijpen van de interne werking van Action Cable — van de levenscyclus van verbindingen tot productie-schaling — een doorslaggevend voordeel ten opzichte van andere kandidaten.

Kernpunt voor Sollicitaties

Action Cable integreert WebSockets in het Rails-framework met dezelfde conventies die worden gebruikt voor controllers en models. Rails 8 introduceert Solid Cable, een database-gebaseerde adapter die de Redis-afhankelijkheid voor pub/sub-messaging elimineert.

Basisprincipes van het WebSocket-Protocol in de Rails-Context

Het WebSocket-protocol (RFC 6455) creëert een persistent, full-duplex communicatiekanaal over een enkele TCP-verbinding. In tegenstelling tot HTTP request-response-cycli houden WebSockets een open verbinding in stand waarbij zowel client als server op elk moment berichten kunnen versturen.

Action Cable verpakt dit protocol in een Rails-compatibele abstractie. De server verwerkt WebSocket-upgrades op /cable, beheert verbindingsauthenticatie en routeert berichten via channels. De JavaScript-bibliotheek aan de clientzijde maakt en beheert subscriptions automatisch.

Een typisch HTTP-verzoek wordt in milliseconden afgehandeld en de verbinding wordt gesloten. Een WebSocket-verbinding blijft daarentegen minuten, uren of de gehele sessieduur open. Dit fundamentele verschil bepaalt elke architectuurbeslissing in Action Cable.

Action Cable-Architectuur: Connections, Channels en Subscriptions

Action Cable volgt een gelaagde architectuur met drie kernabstracties: connections verzorgen authenticatie, channels bevatten de bedrijfslogica, en subscriptions koppelen consumers aan specifieke channels.

ruby
# app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      # Cookies are available in WebSocket handshake
      if verified_user = User.find_by(id: cookies.encrypted[:user_id])
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

De connection-klasse wordt eenmalig uitgevoerd per WebSocket-handshake. Authenticatie vindt hier plaats — niet in individuele channels. De identified_by-declaratie registreert de gebruikersidentiteit en maakt deze beschikbaar in alle channel-subscriptions op die verbinding.

ruby
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    room = ChatRoom.find(params[:room_id])
    # Authorization: verify user belongs to this room
    if room.members.include?(current_user)
      stream_for room
    else
      reject
    end
  end

  def receive(data)
    message = ChatMessage.create!(
      room_id: params[:room_id],
      user: current_user,
      body: data["body"]
    )
    ChatChannel.broadcast_to(
      message.room,
      { id: message.id, body: message.body, user: current_user.name }
    )
  end

  def unsubscribed
    # Cleanup: mark user as offline
    AppearanceTracker.mark_offline(current_user)
  end
end

Channels definiëren drie levenscyclus-callbacks: subscribed, receive en unsubscribed. De methode stream_for bindt de subscription aan een specifieke modelinstantie en creëert een stream met namespace. Broadcasting naar die stream levert berichten af aan elke verbonden subscriber.

Clientzijdige Subscriptions met JavaScript

De clientzijdige consumer maakt verbinding met de Action Cable-server en beheert subscriptions. Elke subscription correspondeert met een channel aan de serverzijde.

app/javascript/channels/chat_channel.jsjavascript
import consumer from "./consumer"

const chatChannel = consumer.subscriptions.create(
  { channel: "ChatChannel", room_id: roomId },
  {
    connected() {
      // Called when the subscription is ready
      console.log("Connected to chat room", roomId)
    },

    disconnected() {
      // Called when the subscription is closed
      console.log("Disconnected from chat room")
    },

    received(data) {
      // Called when data is broadcast to the channel
      const messageList = document.getElementById("messages")
      messageList.insertAdjacentHTML("beforeend",
        `<div class="message"><strong>${data.user}</strong>: ${data.body}</div>`
      )
    },

    sendMessage(body) {
      // Calls ChatChannel#receive on the server
      this.perform("receive", { body: body })
    }
  }
)

De received-callback wordt elke keer geactiveerd wanneer de server naar de geabonneerde stream verstuurt. De perform-methode stuurt gegevens van client naar server en roept de bijbehorende channel-methode aan.

Klaar om je Ruby on Rails gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

Solid Cable in Rails 8: Database-Gebaseerde Pub/Sub

Rails 8 introduceert Solid Cable als onderdeel van de "Solid Trifecta" naast Solid Queue en Solid Cache. Solid Cable vervangt Redis als pub/sub-backend door berichten op te slaan in een databasetabel.

yaml
# config/cable.yml (Rails 8 default)
development:
  adapter: solid_cable

production:
  adapter: solid_cable
  connects_to:
    database:
      writing: cable
  polling_interval: 0.1.seconds
  message_retention: 1.day

Solid Cable werkt door elk broadcast-bericht naar een databasetabel te schrijven en op een configureerbaar interval te pollen voor nieuwe berichten. Het standaard polling-interval van 100ms biedt voor de meeste applicaties een nagenoeg realtime aflevering.

De afweging is duidelijk: Solid Cable elimineert een infrastructuurafhankelijkheid (Redis) ten koste van iets hogere latentie en databasebelasting. Voor applicaties die al PostgreSQL of MySQL draaien, is deze afweging vaak zinvol. Bij hoogfrequente broadcasting (duizenden berichten per seconde) blijft Redis de betere keuze.

ruby
# config/database.yml (Rails 8 multi-database)
production:
  primary:
    <<: *default
    database: myapp_production
  cable:
    <<: *default
    database: myapp_cable_production
    migrations_paths: db/cable_migrate

Solid Cable gebruikt een aparte database om conflicten met de primaire database te voorkomen. Deze scheiding voorkomt dat message-polling interfereert met applicatiequery's.

Broadcasting-Patronen en Serversijdige Triggers

Broadcasting vanuit models, jobs en controllers bestrijkt de drie meest voorkomende patronen in productie Rails-applicaties.

ruby
# Broadcasting from a model callback
class Notification < ApplicationRecord
  belongs_to :user
  after_create_commit :broadcast_to_user

  private

  def broadcast_to_user
    ActionCable.server.broadcast(
      "notifications_#{user_id}",
      { id: id, title: title, read: false }
    )
  end
end

# Broadcasting from a background job
class DashboardUpdateJob < ApplicationJob
  queue_as :default

  def perform(dashboard_id)
    dashboard = Dashboard.find(dashboard_id)
    stats = dashboard.compute_stats
    ActionCable.server.broadcast(
      "dashboard_#{dashboard_id}",
      { stats: stats, updated_at: Time.current.iso8601 }
    )
  end
end

Model-callbacks zijn geschikt voor eenvoudige notificaties die worden geactiveerd door recordwijzigingen. Background jobs verwerken zwaardere berekeningen — zoals dashboardstatistieken of data-aggregaties — zonder de request-cyclus te blokkeren. De broadcast zelf is altijd lichtgewicht: het serialiseert de payload en publiceert deze via de adapter.

Turbo Streams en Action Cable-Integratie

Rails 8 met Hotwire gebruikt Action Cable als transportlaag voor Turbo Streams, waardoor realtime DOM-updates mogelijk worden zonder aangepast JavaScript te schrijven.

ruby
# app/models/message.rb
class Message < ApplicationRecord
  belongs_to :chat_room
  # Automatically broadcasts append to subscribers
  broadcasts_to :chat_room
end

# app/views/chat_rooms/show.html.erb
<%= turbo_stream_from @chat_room %>
<div id="messages">
  <%= render @chat_room.messages %>
</div>

De broadcasts_to-macro genereert after_create-, after_update- en after_destroy-callbacks die Turbo Stream-fragmenten via Action Cable verzenden. De turbo_stream_from-helper aan de clientzijde abonneert zich op de bijbehorende stream. Het aanmaken van een nieuw bericht voegt automatisch de gerenderde partial toe aan de DOM van elke verbonden client.

Dit patroon reduceert realtime functionaliteiten tot een model-declaratie en een view-helper — geen aangepaste channels, geen JavaScript-handlers, geen handmatige DOM-manipulatie.

Schaling van Action Cable in Productie

Productie-deployments vereisen zorgvuldige afwegingen met betrekking tot adapterkeuze, verbindingslimieten en horizontale schaling.

ruby
# config/cable.yml — Redis adapter for high-scale production
production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
  channel_prefix: myapp_production

Redis fungeert als pub/sub-backbone en zorgt ervoor dat berichten die op het ene Rails-proces worden gepubliceerd, subscribers bereiken die met een ander proces zijn verbonden. Zonder Redis (of Solid Cable) beperkt de async-adapter broadcasting tot een enkel proces — onbruikbaar in elke multi-proces of multi-server omgeving.

Verbindingslimieten hangen af van de server. Puma met Action Cable verwerkt WebSocket-verbindingen op hetzelfde proces als HTTP-verzoeken. Elke WebSocket-verbinding houdt een persistente verbinding in stand en verbruikt een thread (of een fiber in Ruby 3.x met fiber-gebaseerde schedulers). Een typische Puma-configuratie met 5 threads en 4 workers kan ongeveer 200 gelijktijdige WebSocket-verbindingen verwerken voordat verzadiging optreedt.

Voor applicaties die duizenden gelijktijdige verbindingen nodig hebben, vervangt AnyCable de Ruby WebSocket-server door een Go-gebaseerde server, die verbindingen op protocolniveau beheert terwijl de channel-logica via gRPC wordt teruggestuurd naar Rails. Deze architectuur ondersteunt meer dan 10.000 gelijktijdige verbindingen per node.

Interview-Inzicht

Interviewers vragen regelmatig naar de schaalbaarheidslimieten van Action Cable. Het kernantwoord: Action Cable zelf is niet het knelpunt — het Ruby-proces dat de WebSocket-verbindingen beheert wel. AnyCable lost dit op door verbindingsbeheer uit te besteden aan Go terwijl de channel-logica in Ruby blijft.

Testen van Action Cable Channels

Rails biedt ActionCable::Channel::TestCase voor het testen van channels en ActionCable::Connection::TestCase voor het testen van verbindingsauthenticatie.

ruby
# test/channels/chat_channel_test.rb
require "test_helper"

class ChatChannelTest < ActionCable::Channel::TestCase
  test "subscribes to a valid room" do
    room = chat_rooms(:general)
    user = users(:alice)
    stub_connection current_user: user

    subscribe room_id: room.id

    assert subscription.confirmed?
    assert_has_stream_for room
  end

  test "rejects subscription for unauthorized user" do
    room = chat_rooms(:private)
    user = users(:outsider)
    stub_connection current_user: user

    subscribe room_id: room.id

    assert subscription.rejected?
  end

  test "broadcasts messages to room subscribers" do
    room = chat_rooms(:general)
    stub_connection current_user: users(:alice)
    subscribe room_id: room.id

    assert_broadcast_on(room, hash_including(body: "Hello")) do
      perform :receive, body: "Hello"
    end
  end
end

De methode stub_connection stelt de verbindingscontext in zonder een echte WebSocket-verbinding. assert_has_stream_for verifieert de stream-binding. assert_broadcast_on vangt broadcasts op binnen een blok en bevestigt dat de juiste payload de juiste stream bereikt.

Veelgestelde Sollicitatievragen over Action Cable

Technische sollicitatiegesprekken over Action Cable toetsen doorgaans het begrip van het protocol, architectuurbeslissingen en productiegerelateerde vraagstukken.

Hoe authenticeert Action Cable verbindingen? Authenticatie vindt plaats in ApplicationCable::Connection#connect tijdens de WebSocket-handshake. Cookies van de HTTP-sessie zijn op dit moment beschikbaar. Token-gebaseerde authenticatie geeft het token door als queryparameter in de WebSocket-URL en valideert het in connect.

Wat gebeurt er wanneer een WebSocket-verbinding wegvalt? De clientbibliotheek implementeert automatische herverbinding met exponentieel backoff. Aan de serverzijde wordt unsubscribed geactiveerd voor elk channel waarop de verbinding was geabonneerd. Stateful opruimacties (gebruikers als offline markeren, locks vrijgeven) horen in unsubscribed.

Wanneer moet Solid Cable worden gebruikt in plaats van Redis? Solid Cable is geschikt voor applicaties met gematigde realtime behoeften (minder dan 100 berichten/seconde) die Redis-infrastructuur willen vermijden. Redis blijft noodzakelijk voor scenario's met hoge doorvoer of wanneer een afleveringslatentie van minder dan 10ms vereist is.

Veelgemaakte Fout

Autorisatielogica in de connection-klasse plaatsen in plaats van in individuele channels. De connection authenticeert de identiteit (Wie is deze gebruiker?). Channels autoriseren de toegang (Mag deze gebruiker deze ruimte betreden?). Het vermengen van deze verantwoordelijkheden creëert beveiligingslekken.

Conclusie

  • Action Cable verpakt het WebSocket-protocol in Rails-conventies met connections, channels en subscriptions als kernabstracties
  • Authenticatie hoort in ApplicationCable::Connection; autorisatie hoort in de subscribed-callbacks van individuele channels
  • Solid Cable in Rails 8 elimineert de Redis-afhankelijkheid door de database te gebruiken voor pub/sub — geschikt voor applicaties met gematigde doorvoer
  • Turbo Streams benutten Action Cable voor automatische realtime DOM-updates met minimale code
  • Productieschaling vereist Redis of Solid Cable voor multi-proces deployments; AnyCable verwerkt meer dan 10.000 verbindingen door WebSocket-beheer uit te besteden aan Go
  • Het testen van channels maakt gebruik van stub_connection, assert_has_stream_for en assert_broadcast_on — geen echte WebSocket-verbindingen nodig
  • Oefen ActionCable- en WebSocket-sollicitatievragen om deze concepten te versterken met gerichte oefeningen

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Tags

#ruby-on-rails
#action-cable
#websockets
#real-time
#interviews

Delen

Gerelateerde artikelen