Introdução

Se você já quis que seu aplicativo Rails parecesse vivo, você deve conferir Action Cable. É a maneira integrada do Rails de fazer WebSockets, o que basicamente significa que seu servidor e o navegador podem permanecer conectados e conversar em tempo real. Chega de atualizações de página, sem polling desajeitado — as atualizações aparecem instantaneamente.

Neste guia, vamos construir uma demonstração divertida: um contador de tráfego ao vivo. Quando alguém acessa seu site, vamos registrar essa visita no banco de dados, aumentar alguns contadores na memória e transmitir os números atualizados para todos online. Fechou a aba? A contagem de usuários online cai imediatamente. É simples, mas mostra a mágica em tempo real que o Action Cable traz para o Rails 7.

Passo 1: O Modelo de Visita

Primeiro, vamos criar um modelo para registrar visitas.

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

Passo 2: Criando uma Conexão Personalizada

O Rails já te dá duas classes base em app/channels/application_cable/:
- channel.rb → a classe base para todos os seus canais.
- connection.rb → a classe base para todas as suas conexões WebSocket.

Normalmente, não editamos essas classes. Em vez disso, as estendemos criando nossa própria classe de conexão dentro de app/channels/. Isso mantém os padrões limpos e coloca nossa lógica em um lugar claro.

# 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

Passo 3: Contadores na Memória

Usaremos contadores atômicos para tornar as coisas rápidas. Na inicialização, pegamos o total de visitas do DB e começamos a contagem de usuários online em zero.

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

Passo 4: O Canal

Aqui é onde a diversão acontece — registre a visita, atualize os contadores e transmita.

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

    # atualizar contadores
    $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

Passo 5: O Lado do JavaScript

Quando você executa bin/rails generate channel Traffic, o Rails cria dois arquivos: o canal Ruby e o arquivo de assinatura JavaScript. Por padrão, o arquivo JS importa consumer.js, que o Rails também configurou para você quando o aplicativo foi gerado.

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

O arquivo consumer.js é gerado pelo Rails quando você cria um novo aplicativo. Ele configura a conexão global WebSocket para /cable e se parece com isso:

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

export default createConsumer()

Passo 6: A Visualização

<h1>🚦 Tráfego Ao Vivo</h1>
<p>Atualmente online: <span id="online-count">0</span></p>
<p>Total de visitas: <span id="total-count"><%= Visit.count %></span></p>

Passo 7: Rotas

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

Passo 8: Experimente

Execute seu aplicativo com bin/dev. Abra seu site em algumas abas. O contador de usuários online aumenta com cada uma delas e diminui quando você as fecha. O total de visitas continua subindo. Super satisfatório de assistir! 

Notas para Produção

- Múltiplos trabalhadores Puma? Use Redis para contadores — a memória não será sincronizada entre processos.
- Quer rastrear usuários reais em vez de sessões? Adicione current_user na conexão.
- Armazenar visitas no DB significa que você pode executar análises depois, como tráfego diário ou divisões de navegador.

E é isso — um contador de tráfego ao vivo em tempo real no Rails 7 com Action Cable. Em menos de 100 linhas de código, você tem atualizações instantâneas e um gostinho do que os WebSockets podem fazer. Essa mesma configuração funciona para notificações, painéis e todos os tipos de recursos em tempo real. Uma vez que você experimentou, vai querer espalhar isso por toda parte.