Section 13.5.4 : Action Cable et temps réel
🎯 Objectif pédagogique
Intégrer le temps réel dans une application Rails avec Action Cable (WebSockets) pour créer des fonctionnalités comme le chat en direct, les notifications instantanées et les mises à jour live.
WebSockets vs HTTP classique
HTTP classique est un protocole requête-réponse : le client demande, le serveur répond, la connexion se ferme. WebSocket maintient une connexion permanente et bidirectionnelle entre client et serveur.
Action Cable : WebSockets intégré à Rails
Action Cable est la couche WebSocket de Rails. Il s'intègre nativement avec le reste du framework.
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
def subscribed
stream_from "chat_#{params[:room_id]}"
end
def unsubscribed
# Nettoyage si nécessaire
end
def receive(data)
# Quand le client envoie un message
message = Message.create!(
content: data['content'],
user: current_user,
room_id: params[:room_id]
)
ActionCable.server.broadcast(
"chat_#{params[:room_id]}",
{
content: message.content,
user: message.user.name,
created_at: message.created_at.strftime('%H:%M')
}
)
end
end
Côté JavaScript
// app/javascript/channels/chat_channel.js
import consumer from './consumer'
const chatChannel = consumer.subscriptions.create(
{ channel: 'ChatChannel', room_id: 1 },
{
connected() {
console.log('Connecté au chat !')
},
disconnected() {
console.log('Déconnecté du chat')
},
received(data) {
// Appelé quand le serveur broadcast un message
const messagesDiv = document.querySelector('#messages')
messagesDiv.insertAdjacentHTML('beforeend', `
<div class="message">
<strong>${data.user}</strong>
<span class="time">${data.created_at}</span>
<p>${data.content}</p>
</div>
`)
messagesDiv.scrollTop = messagesDiv.scrollHeight
},
// Envoyer un message au serveur
sendMessage(content) {
this.perform('receive', { content })
}
}
)
// Formulaire d envoi
document.querySelector('#message-form').addEventListener('submit', (e) => {
e.preventDefault()
const input = e.target.querySelector('input')
chatChannel.sendMessage(input.value)
input.value = ''
})
Broadcast depuis un Model
La manière la plus courante d'utiliser Action Cable est de broadcaster depuis un callback de modèle :
# app/models/message.rb
class Message < ApplicationRecord
belongs_to :user
belongs_to :room
after_create_commit :broadcast_message
private
def broadcast_message
ActionCable.server.broadcast(
"chat_#{room_id}",
{
content: content,
user: user.name,
html: ApplicationController.render(
partial: 'messages/message',
locals: { message: self }
)
}
)
end
end
Turbo Streams : le temps réel simplifié
Avec Hotwire/Turbo, le temps réel devient encore plus simple :
# app/models/message.rb
class Message < ApplicationRecord
broadcasts_to :room # UNE SEULE LIGNE !
end
<!-- app/views/rooms/show.html.erb -->
<%= turbo_stream_from @room %>
<div id="messages">
<%= render @room.messages %>
</div>
<%= turbo_frame_tag 'new_message' do %>
<%= render 'messages/form', message: Message.new(room: @room) %>
<% end %>
Turbo Streams vs Action Cable brut
Turbo Streams est une abstraction au-dessus d'Action Cable qui génère automatiquement le HTML côté serveur et le met à jour côté client. Pour la plupart des cas d'usage, Turbo Streams est le choix préféré car il élimine le JavaScript côté client.
Quel est l'avantage principal de Turbo Streams par rapport à Action Cable brut ?
Learn AI, from prompts to agents