Action Cable und WebSockets in Rails: Umfassender Leitfaden für technische Vorstellungsgespräche 2026

Action Cable im Detail für Rails-Interviews. Verbindungen, Channels, Solid Cable, Turbo Streams, Skalierung mit Redis und Testmuster mit Codebeispielen.

Action Cable und WebSockets in Rails

Action Cable bringt WebSocket-Unterstützung direkt in das Rails-Framework und ermöglicht Echtzeit-Funktionen wie Chat, Benachrichtigungen und Live-Dashboards ohne externe Abhängigkeiten. Für technische Vorstellungsgespräche im Jahr 2026 ist das Verständnis der Action Cable-Interna — vom Verbindungslebenszyklus bis zur Produktionsskalierung — ein entscheidender Vorteil gegenüber anderen Bewerbern.

Wichtige Erkenntnis für Interviews

Action Cable integriert WebSockets in das Rails-Framework mit denselben Konventionen, die auch für Controller und Models verwendet werden. Rails 8 führt Solid Cable ein, einen datenbankbasierten Adapter, der die Redis-Abhängigkeit für Pub/Sub-Messaging eliminiert.

Grundlagen des WebSocket-Protokolls im Rails-Kontext

Das WebSocket-Protokoll (RFC 6455) stellt einen persistenten, vollduplexfähigen Kommunikationskanal über eine einzelne TCP-Verbindung her. Im Gegensatz zu HTTP-Request-Response-Zyklen hält eine WebSocket-Verbindung den Kanal offen, sodass sowohl Client als auch Server jederzeit Nachrichten senden können.

Action Cable kapselt dieses Protokoll in eine Rails-kompatible Abstraktion. Der Server übernimmt WebSocket-Upgrades unter /cable, verwaltet die Verbindungsauthentifizierung und leitet Nachrichten über Channels weiter. Die clientseitige JavaScript-Bibliothek erstellt und verwaltet Subscriptions automatisch.

Eine typische HTTP-Anfrage wird in Millisekunden abgeschlossen und die Verbindung geschlossen. Eine WebSocket-Verbindung bleibt dagegen Minuten, Stunden oder die gesamte Sitzungsdauer offen. Dieser grundlegende Unterschied beeinflusst jede architektonische Entscheidung in Action Cable.

Action Cable-Architektur: Connections, Channels und Subscriptions

Action Cable folgt einer mehrschichtigen Architektur mit drei zentralen Abstraktionen: Connections übernehmen die Authentifizierung, Channels kapseln die Geschäftslogik, und Subscriptions verbinden Consumer mit bestimmten 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

Die Connection-Klasse wird einmalig pro WebSocket-Handshake ausgeführt. Die Authentifizierung findet hier statt — nicht in den einzelnen Channels. Die identified_by-Deklaration registriert die Benutzeridentität und macht sie über alle Channel-Subscriptions dieser Verbindung verfügbar.

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 definieren drei Lebenszyklus-Callbacks: subscribed, receive und unsubscribed. Die Methode stream_for bindet die Subscription an eine bestimmte Modellinstanz und erstellt einen namensgebundenen Stream. Das Broadcasting an diesen Stream übermittelt Nachrichten an jeden verbundenen Subscriber.

Clientseitige Subscriptions mit JavaScript

Der clientseitige Consumer verbindet sich mit dem Action Cable-Server und verwaltet Subscriptions. Jede Subscription entspricht einem serverseitigen Channel.

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 })
    }
  }
)

Der received-Callback wird jedes Mal ausgelöst, wenn der Server an den abonnierten Stream sendet. Die perform-Methode sendet Daten vom Client an den Server und ruft die entsprechende Channel-Methode auf.

Bereit für deine Ruby on Rails-Interviews?

Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.

Solid Cable in Rails 8: Datenbankbasiertes Pub/Sub

Rails 8 führt Solid Cable als Teil der "Solid-Trilogie" neben Solid Queue und Solid Cache ein. Solid Cable ersetzt Redis als Pub/Sub-Backend, indem es Nachrichten in einer Datenbanktabelle speichert.

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 funktioniert, indem jede Broadcast-Nachricht in eine Datenbanktabelle geschrieben und in einem konfigurierbaren Intervall nach neuen Nachrichten gepollt wird. Das Standard-Polling-Intervall von 100ms bietet für die meisten Anwendungen eine nahezu Echtzeit-Zustellung.

Der Kompromiss ist klar: Solid Cable eliminiert eine Infrastrukturabhängigkeit (Redis) auf Kosten etwas höherer Latenz und Datenbankbelastung. Für Anwendungen, die bereits PostgreSQL oder MySQL betreiben, ist dieser Kompromiss oft sinnvoll. Bei hochfrequentem Broadcasting (tausende Nachrichten pro Sekunde) bleibt Redis die bessere Wahl.

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 verwendet eine dedizierte Datenbank, um Konflikte mit der primären Datenbank zu vermeiden. Diese Trennung verhindert, dass Message-Polling die Anwendungsabfragen beeinträchtigt.

Broadcasting-Muster und serverseitige Trigger

Das Broadcasting aus Models, Jobs und Controllern deckt die drei häufigsten Muster in produktiven Rails-Anwendungen ab.

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 eignen sich für einfache Benachrichtigungen, die durch Datensatzänderungen ausgelöst werden. Background Jobs übernehmen aufwändigere Berechnungen — wie Dashboard-Statistiken oder Datenaggregationen — ohne den Request-Zyklus zu blockieren. Der Broadcast selbst ist immer leichtgewichtig: Er serialisiert die Payload und veröffentlicht sie über den Adapter.

Turbo Streams und Action Cable-Integration

Rails 8 mit Hotwire nutzt Action Cable als Transportschicht für Turbo Streams und ermöglicht Echtzeit-DOM-Updates ohne eigenes JavaScript.

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>

Das broadcasts_to-Makro generiert after_create-, after_update- und after_destroy-Callbacks, die Turbo Stream-Fragmente über Action Cable senden. Der turbo_stream_from-Helper auf der Client-Seite abonniert den passenden Stream. Das Erstellen einer neuen Nachricht hängt automatisch ihr gerendertes Partial an das DOM jedes verbundenen Clients an.

Dieses Muster reduziert Echtzeit-Features auf eine Model-Deklaration und einen View-Helper — keine eigenen Channels, keine JavaScript-Handler, keine manuelle DOM-Manipulation.

Skalierung von Action Cable in der Produktion

Produktionsdeployments erfordern sorgfältige Überlegungen bezüglich Adapter-Wahl, Verbindungslimits und horizontaler Skalierung.

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 fungiert als Pub/Sub-Backbone und stellt sicher, dass Nachrichten, die auf einem Rails-Prozess veröffentlicht werden, Subscriber erreichen, die mit einem anderen Prozess verbunden sind. Ohne Redis (oder Solid Cable) beschränkt der Async-Adapter das Broadcasting auf einen einzelnen Prozess — unbrauchbar in jeder Mehrprozess- oder Mehrserver-Umgebung.

Verbindungslimits hängen vom Server ab. Puma mit Action Cable verarbeitet WebSocket-Verbindungen auf demselben Prozess wie HTTP-Anfragen. Jede WebSocket-Verbindung hält eine persistente Verbindung aufrecht und verbraucht einen Thread (oder eine Fiber in Ruby 3.x mit fiberbasierten Schedulern). Eine typische Puma-Konfiguration mit 5 Threads und 4 Workern kann ungefähr 200 gleichzeitige WebSocket-Verbindungen verarbeiten, bevor es zur Sättigung kommt.

Für Anwendungen, die Tausende gleichzeitiger Verbindungen benötigen, ersetzt AnyCable den Ruby-WebSocket-Server durch einen Go-basierten Server, der Verbindungen auf Protokollebene verwaltet und die Channel-Logik über gRPC zurück an Rails leitet. Diese Architektur unterstützt über 10.000 gleichzeitige Verbindungen pro Knoten.

Interview-Einblick

Interviewer fragen häufig nach den Skalierungsgrenzen von Action Cable. Die entscheidende Antwort: Action Cable selbst ist nicht der Engpass — der Ruby-Prozess, der die WebSocket-Verbindungen verwaltet, ist es. AnyCable löst dieses Problem, indem es die Verbindungsverwaltung an Go auslagert und gleichzeitig die Channel-Logik in Ruby belässt.

Testen von Action Cable Channels

Rails stellt ActionCable::Channel::TestCase für Unit-Tests von Channels und ActionCable::Connection::TestCase für das Testen der Verbindungsauthentifizierung bereit.

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

Die Methode stub_connection richtet den Verbindungskontext ohne echte WebSocket-Verbindung ein. assert_has_stream_for überprüft die Stream-Bindung. assert_broadcast_on erfasst Broadcasts innerhalb eines Blocks und bestätigt, dass die korrekte Payload den richtigen Stream erreicht.

Häufige Interview-Fragen zu Action Cable

Technische Interviews zu Action Cable prüfen typischerweise das Verständnis des Protokolls, architektonischer Entscheidungen und produktionsbezogener Themen.

Wie authentifiziert Action Cable Verbindungen? Die Authentifizierung findet in ApplicationCable::Connection#connect während des WebSocket-Handshakes statt. Cookies aus der HTTP-Session sind zu diesem Zeitpunkt verfügbar. Bei tokenbasierter Authentifizierung wird das Token als Query-Parameter in der WebSocket-URL übergeben und in connect validiert.

Was passiert, wenn eine WebSocket-Verbindung abbricht? Die Client-Bibliothek implementiert automatische Wiederverbindung mit exponentiellem Backoff. Auf der Serverseite wird unsubscribed für jeden Channel ausgelöst, den die Verbindung abonniert hatte. Zustandsbezogene Bereinigungen (Benutzer als offline markieren, Sperren freigeben) gehören in unsubscribed.

Wann sollte Solid Cable anstelle von Redis verwendet werden? Solid Cable eignet sich für Anwendungen mit moderatem Echtzeit-Bedarf (unter 100 Nachrichten/Sekunde), die Redis-Infrastruktur vermeiden möchten. Redis bleibt für Hochdurchsatz-Szenarien oder wenn eine Zustelllatenz unter 10ms erforderlich ist, notwendig.

Häufiger Fehler

Autorisierungslogik in die Connection-Klasse statt in einzelne Channels zu platzieren. Die Connection authentifiziert die Identität (Wer ist dieser Benutzer?). Channels autorisieren den Zugriff (Darf dieser Benutzer auf diesen Raum zugreifen?). Die Vermischung dieser Verantwortlichkeiten schafft Sicherheitslücken.

Fazit

  • Action Cable kapselt das WebSocket-Protokoll in Rails-Konventionen mit Connections, Channels und Subscriptions als zentrale Abstraktionen
  • Authentifizierung gehört in ApplicationCable::Connection; Autorisierung gehört in die subscribed-Callbacks einzelner Channels
  • Solid Cable in Rails 8 eliminiert die Redis-Abhängigkeit durch Nutzung der Datenbank für Pub/Sub — geeignet für Anwendungen mit moderatem Durchsatz
  • Turbo Streams nutzen Action Cable für automatische Echtzeit-DOM-Updates mit minimalem Code
  • Produktionsskalierung erfordert Redis oder Solid Cable für Mehrprozess-Deployments; AnyCable verarbeitet über 10.000 Verbindungen durch Auslagerung der WebSocket-Verwaltung an Go
  • Das Testen von Channels nutzt stub_connection, assert_has_stream_for und assert_broadcast_on — keine echten WebSocket-Verbindungen erforderlich
  • ActionCable- und WebSocket-Interviewfragen üben, um diese Konzepte mit gezielten Übungen zu festigen

Fang an zu üben!

Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.

Tags

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

Teilen

Verwandte Artikel