# Action Cable et WebSockets dans Rails : Guide Complet pour les Entretiens Techniques > Action Cable integre les WebSockets directement dans Rails. Ce guide approfondi couvre l'architecture des connexions, les channels, Solid Cable, Turbo Streams, le scaling avec Redis et les patterns de test pour les entretiens techniques. - Published: 2026-05-07 - Updated: 2026-05-07 - Author: SharpSkill - Tags: ruby on rails, action cable, websockets, temps reel, solid cable, rails 8 - Reading time: 11 min --- Action Cable représente l'intégration native des WebSockets dans Ruby on Rails, permettant d'établir des connexions bidirectionnelles persistantes entre le serveur et les clients. Cette technologie constitue un pilier fondamental pour le développement d'applications temps réel modernes. Les recruteurs évaluent fréquemment la compréhension des candidats sur ce sujet, car la maîtrise d'Action Cable témoigne d'une expertise approfondie de l'écosystème Rails et des architectures événementielles. > Les questions d'entretien sur Action Cable visent généralement trois axes : l'architecture des connexions et channels, les stratégies de diffusion (broadcasting), et la configuration en production. Une préparation solide sur ces trois piliers permet de démontrer une compréhension complète du framework. ## Architecture et Authentification des Connexions Le point d'entrée d'Action Cable réside dans la classe `Connection`, responsable de l'authentification et de l'identification de chaque connexion WebSocket. Contrairement aux requêtes HTTP classiques, une connexion WebSocket persiste dans le temps, rendant l'authentification initiale cruciale pour la sécurité de l'application. ```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 if verified_user = User.find_by(id: cookies.encrypted[:user_id]) verified_user else reject_unauthorized_connection end end end end ``` La directive `identified_by` établit un identifiant unique pour chaque connexion, permettant de cibler des utilisateurs spécifiques lors des diffusions. La méthode `find_verified_user` illustre l'approche recommandée : utiliser des cookies chiffrés plutôt que des paramètres d'URL, évitant ainsi l'exposition des tokens d'authentification dans les logs serveur. L'appel à `reject_unauthorized_connection` ferme immédiatement la connexion WebSocket et déclenche une erreur côté client. Cette approche défensive garantit qu'aucune connexion non authentifiée ne puisse s'établir, même partiellement. ## Conception des Channels et Gestion des Abonnements Les channels constituent l'abstraction principale pour organiser la logique temps réel. Chaque channel encapsule un domaine fonctionnel spécifique et gère le cycle de vie des abonnements ainsi que la réception des messages. ```ruby # app/channels/chat_channel.rb class ChatChannel < ApplicationCable::Channel def subscribed room = ChatRoom.find(params[:room_id]) 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 AppearanceTracker.mark_offline(current_user) end end ``` La méthode `subscribed` effectue une vérification d'autorisation avant d'établir le stream. L'utilisation de `stream_for` avec un objet Active Record génère automatiquement un nom de stream unique basé sur le modèle, simplifiant la gestion des identifiants. La méthode `receive` traite les messages entrants des clients. Elle persiste le message en base de données puis le diffuse à tous les abonnés du salon. Cette séparation entre persistance et diffusion permet de garantir la cohérence des données même en cas de déconnexion temporaire. Le callback `unsubscribed` gère le nettoyage lors de la fermeture de connexion, permettant par exemple de mettre à jour le statut de présence des utilisateurs. ## Intégration JavaScript Côté Client L'établissement de la connexion WebSocket côté client s'effectue via le consumer JavaScript fourni par Rails. La configuration des callbacks permet de réagir aux différents événements du cycle de vie de la connexion. ```javascript // app/javascript/channels/chat_channel.js import consumer from "./consumer" const chatChannel = consumer.subscriptions.create( { channel: "ChatChannel", room_id: roomId }, { connected() { console.log("Connected to chat room", roomId) }, disconnected() { console.log("Disconnected from chat room") }, received(data) { const messageList = document.getElementById("messages") messageList.insertAdjacentHTML("beforeend", `
` ) }, sendMessage(body) { this.perform("receive", { body: body }) } } ) ``` Le premier argument de `subscriptions.create` spécifie le channel et les paramètres transmis à la méthode `subscribed` côté serveur. Les callbacks `connected` et `disconnected` permettent d'adapter l'interface utilisateur selon l'état de la connexion. La méthode `received` traite les messages diffusés par le serveur, tandis que `sendMessage` illustre l'envoi de données vers le serveur via `this.perform`. Cette méthode invoque la méthode correspondante dans le channel Ruby. ## Solid Cable : L'Adaptateur Natif de Rails 8 Rails 8 introduit Solid Cable comme adaptateur par défaut, éliminant la dépendance à Redis pour de nombreux cas d'usage. Solid Cable utilise la base de données existante pour la messagerie, simplifiant considérablement l'infrastructure de déploiement. ```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 ``` La configuration multi-base de données permet d'isoler les opérations Action Cable sur une base dédiée, évitant toute contention avec les requêtes applicatives principales. ```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 ``` Cette séparation offre plusieurs avantages : les opérations de polling fréquentes n'impactent pas les performances de la base principale, et la rétention des messages peut être configurée indépendamment. Le paramètre `message_retention` permet de purger automatiquement les anciens messages, maintenant une empreinte mémoire maîtrisée. ## Stratégies de Diffusion et Patterns Courants La diffusion de messages peut s'effectuer depuis différents contextes applicatifs. Les callbacks de modèle permettent de déclencher des notifications automatiques lors des modifications de données. ```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 ``` L'utilisation de `after_create_commit` garantit que la diffusion n'intervient qu'après la validation de la transaction, évitant de notifier les clients pour des données qui pourraient être annulées par un rollback. Les jobs en arrière-plan conviennent particulièrement aux calculs coûteux dont les résultats doivent être diffusés. Cette approche découple le calcul de la diffusion et permet un meilleur contrôle de la charge serveur. ## Intégration avec Turbo Streams Hotwire Turbo simplifie drastiquement l'implémentation du temps réel en automatisant la diffusion et le rendu des mises à jour. ```ruby # app/models/message.rb class Message < ApplicationRecord belongs_to :chat_room broadcasts_to :chat_room end # app/views/chat_rooms/show.html.erb <%= turbo_stream_from @chat_room %>