Einführung

Wenn du jemals wolltest, dass deine Rails-App lebendig wirkt, solltest du dir Action Cable ansehen. Es ist Rails’ integrierte Methode, um WebSockets zu nutzen, was bedeutet, dass dein Server und der Browser verbunden bleiben und in Echtzeit kommunizieren können. Keine Seitenaktualisierungen mehr, kein umständliches Polling — Updates erscheinen sofort.

In diesem Leitfaden bauen wir eine kleine, unterhaltsame Demo: einen Live-Traffic-Zähler. Wenn jemand deine Seite besucht, protokollieren wir diesen Besuch in der Datenbank, erhöhen einige Zähler im Speicher und senden die aktualisierten Zahlen an alle Online-Nutzer. Schließt du den Tab? Die Anzahl der Online-Nutzer sinkt sofort. Es ist einfach, aber es zeigt die Echtzeit-Magie, die Action Cable in Rails 7 bringt.

Schritt 1: Das Besuchsmodell

Zuerst erstellen wir ein Modell, um Besuche zu protokollieren.

bin/rails g model Visit session_id:string ip:string user_agent:string
bin/rails db:migrate
# app/models/visit.rb
class Visit < ApplicationRecord
end

Schritt 2: Eine benutzerdefinierte Verbindung erstellen

Rails bietet dir bereits zwei Basis-Klassen in app/channels/application_cable/:
- channel.rb → die Basis-Klasse für all deine Kanäle.
- connection.rb → die Basis-Klasse für all deine WebSocket-Verbindungen.

Normalerweise bearbeiten wir diese nicht. Stattdessen erweitern wir sie, indem wir unsere eigene Verbindungs-Klasse innerhalb von app/channels/ erstellen. So bleiben die Standardwerte sauber und unsere Logik ist an einem klaren Ort.

# app/channels/traffic_connection.rb
module ApplicationCable
  class TrafficConnection < Connection
    identified_by :session_id, :ip, :user_agent

    def connect
      self.session_id = request.session.id
      self.ip         = request.ip
      self.user_agent = request.user_agent
    end
  end
end

Schritt 3: Zähler im Speicher

Wir verwenden atomare Zähler, um die Dinge schnell zu machen. Beim Start holen wir die Gesamtbesuche aus der DB und starten die Online-Nutzer bei null.

# config/initializers/traffic_counter.rb
$online_users = Concurrent::AtomicFixnum.new(0)
$total_visits = Concurrent::AtomicFixnum.new(Visit.count)

Schritt 4: Der Kanal

Hier passiert der Spaß — protokolliere den Besuch, aktualisiere die Zähler und sende die Daten.

# app/channels/traffic_channel.rb
class TrafficChannel < ApplicationCable::Channel
  def subscribed
    # Besuch protokollieren
    Visit.create!(session_id: connection.session_id,
                  ip: connection.ip,
                  user_agent: connection.user_agent)

    # Zähler aktualisieren
    $online_users.increment
    $total_visits.increment

    stream_from "traffic_channel"
    broadcast_counts
  end

  def unsubscribed
    $online_users.decrement
    broadcast_counts
  end

  private

  def broadcast_counts
    ActionCable.server.broadcast("traffic_channel", {
      online: $online_users.value,
      total:  $total_visits.value
    })
  end
end

Schritt 5: Die JavaScript-Seite

Wenn du bin/rails generate channel Traffic ausführst, erstellt Rails zwei Dateien: die Ruby-Kanal-Datei und die JavaScript-Subscriptions-Datei. Standardmäßig importiert die JS-Datei consumer.js, das Rails ebenfalls für dich eingerichtet hat, als die App generiert wurde.

// app/javascript/channels/traffic_channel.js
import consumer from "./consumer"

consumer.subscriptions.create("TrafficChannel", {
  received(data) {
    document.querySelector("#online-count").textContent = data.online
    document.querySelector("#total-count").textContent = data.total
  }
})

Die consumer.js-Datei wird von Rails generiert, wenn du eine neue App erstellst. Sie richtet die globale WebSocket-Verbindung zu /cable ein und sieht so aus:

// app/javascript/channels/consumer.js
import { createConsumer } from "@rails/actioncable"

export default createConsumer()

Schritt 6: Die Ansicht

<h1>🚦 Live Traffic</h1>
<p>Aktuell online: <span id="online-count">0</span></p>
<p>Gesamtbesuche: <span id="total-count"><%= Visit.count %></span></p>

Schritt 7: Routen

# config/routes.rb
Rails.application.routes.draw do
  root "home#index"
  mount ActionCable.server => "/cable"
end

Schritt 8: Probier es aus

Starte deine App mit bin/dev. Öffne deine Seite in ein paar Tabs. Der Zähler für Online-Nutzer steigt mit jedem Tab und sinkt, wenn du sie schließt. Die Gesamtbesuche steigen einfach weiter. Super befriedigend zu beobachten! 

Hinweise für die Produktion

- Mehrere Puma-Worker? Verwende Redis für die Zähler — der Speicher wird nicht zwischen Prozessen synchronisiert.
- Möchtest du tatsächliche Nutzer anstelle von Sitzungen verfolgen? Füge current_user in der Verbindung hinzu.
- Das Speichern von Besuchen in der DB bedeutet, dass du später Analysen durchführen kannst, wie täglicher Traffic oder Browser-Verteilungen.

Und das war's — ein Echtzeit-Live-Traffic-Zähler in Rails 7 mit Action Cable. In weniger als 100 Zeilen Code hast du sofortige Updates und einen Vorgeschmack darauf, was WebSockets leisten können. Dasselbe Setup funktioniert für Benachrichtigungen, Dashboards und allerlei Echtzeit-Funktionen. Wenn du es einmal ausprobiert hast, wirst du es überall einsetzen wollen.