# Action Cable i WebSockety w Rails: Kompletny przewodnik na rozmowy techniczne 2026 > Dogłębna analiza Action Cable i WebSocketów w Ruby on Rails. Połączenia, kanały, broadcasting, Solid Cable w Rails 8, skalowanie z Redis oraz najczęstsze pytania na rozmowach kwalifikacyjnych z przykładami kodu. - Published: 2026-05-07 - Updated: 2026-05-07 - Author: Anthony Fillion-Maillet - Tags: ruby on rails, action cable, websockets, real-time, solid cable, rails 8 - Reading time: 11 min --- Action Cable wprowadza obsługę WebSocketów bezpośrednio do frameworka Rails, umożliwiając budowanie funkcjonalności czasu rzeczywistego — czatu, powiadomień czy dashboardów na żywo — bez zewnętrznych zależności. Na rozmowach technicznych w 2026 roku znajomość wewnętrznych mechanizmów Action Cable, od cyklu życia połączenia po skalowanie na produkcji, wyróżnia silnych kandydatów. > **Kluczowy wniosek na rozmowę** > > Action Cable integruje WebSockety z frameworkiem Rails, stosując te same konwencje co kontrolery i modele. Rails 8 wprowadza Solid Cable — adapter oparty na bazie danych, eliminujący konieczność korzystania z Redisa do obsługi pub/sub. ## Podstawy protokołu WebSocket w kontekście Rails Protokół WebSocket (RFC 6455) ustanawia trwałe, dwukierunkowe połączenie komunikacyjne przez pojedyncze połączenie TCP. W przeciwieństwie do cyklu żądanie-odpowiedź w HTTP, WebSockety utrzymują otwarte połączenie, w którym zarówno klient, jak i serwer mogą wysyłać wiadomości w dowolnym momencie. Action Cable opakowuje ten protokół w abstrakcję przyjazną dla Rails. Serwer obsługuje aktualizację połączenia do WebSocket pod adresem `/cable`, zarządza uwierzytelnianiem połączeń i kieruje wiadomości przez kanały. Biblioteka JavaScript po stronie klienta automatycznie tworzy i zarządza subskrypcjami. Typowe żądanie HTTP kończy się w milisekundach i zamyka połączenie. Połączenie WebSocket pozostaje otwarte przez minuty, godziny lub całą sesję użytkownika. Ta fundamentalna różnica determinuje każdą decyzję architektoniczną w Action Cable. ## Architektura Action Cable: połączenia, kanały i subskrypcje Action Cable stosuje warstwową architekturę z trzema głównymi abstrakcjami: połączenia obsługują uwierzytelnianie, kanały enkapsulują logikę biznesową, a subskrypcje łączą konsumentów z konkretnymi kanałami. ```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 ``` Klasa połączenia uruchamia się jednokrotnie przy handshaku WebSocket. Uwierzytelnianie odbywa się właśnie tutaj — nie w poszczególnych kanałach. Deklaracja `identified_by` rejestruje tożsamość użytkownika, udostępniając ją we wszystkich subskrypcjach kanałów w danym połączeniu. ```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 ``` Kanały definiują trzy callbacki cyklu życia: `subscribed`, `receive` i `unsubscribed`. Metoda `stream_for` wiąże subskrypcję z konkretną instancją modelu, tworząc strumień z przestrzenią nazw. Broadcasting do tego strumienia dostarcza wiadomości do każdego podłączonego subskrybenta. ## Subskrypcje po stronie klienta w JavaScript Konsument po stronie klienta łączy się z serwerem Action Cable i zarządza subskrypcjami. Każda subskrypcja odpowiada kanałowi po stronie serwera. ```javascript // app/javascript/channels/chat_channel.js 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", `
${data.user}: ${data.body}
` ) }, sendMessage(body) { // Calls ChatChannel#receive on the server this.perform("receive", { body: body }) } } ) ``` Callback `received` uruchamia się za każdym razem, gdy serwer broadcastuje do subskrybowanego strumienia. Metoda `perform` wysyła dane od klienta do serwera, wywołując odpowiednią metodę kanału. ## Solid Cable w Rails 8: pub/sub oparty na bazie danych Rails 8 wprowadza Solid Cable jako element "Solid Trifecta" obok Solid Queue i Solid Cache. Solid Cable zastępuje Redisa jako backend pub/sub, przechowując wiadomości w tabeli bazy danych. ```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 działa poprzez zapis każdej wiadomości broadcast do tabeli bazy danych i odpytywanie o nowe wiadomości w konfigurowalnym interwale. Domyślny interwał 100ms zapewnia dostarczanie niemal w czasie rzeczywistym dla większości aplikacji. Kompromis jest jasny: Solid Cable eliminuje zależność infrastrukturalną (Redis) kosztem nieco wyższego opóźnienia i obciążenia bazy danych. Dla aplikacji już korzystających z PostgreSQL lub MySQL ten kompromis często ma sens. Przy wysoko-częstotliwościowym broadcastingu (tysiące wiadomości na sekundę) Redis pozostaje lepszym wyborem. ```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 wykorzystuje dedykowaną bazę danych, aby uniknąć rywalizacji z bazą główną. To rozdzielenie zapobiega wpływowi odpytywania o wiadomości na zapytania aplikacji. ## Wzorce broadcastingu i triggery po stronie serwera Broadcasting z modeli, zadań w tle i kontrolerów obejmuje trzy najczęstsze wzorce w produkcyjnych aplikacjach Rails. ```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 ``` Callbacki modelu nadają się do prostych powiadomień wywoływanych zmianami rekordów. Zadania w tle obsługują cięższe obliczenia — wyliczanie statystyk dashboardu czy agregowanie danych — bez blokowania cyklu żądania. Sam broadcast jest zawsze lekki: serializuje payload i publikuje go do adaptera. ## Turbo Streams i integracja z Action Cable Rails 8 z Hotwire wykorzystuje Action Cable jako warstwę transportową dla Turbo Streams, umożliwiając aktualizacje DOM w czasie rzeczywistym bez pisania własnego JavaScriptu. ```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 %>
<%= render @chat_room.messages %>
``` Makro `broadcasts_to` generuje callbacki after_create, after_update i after_destroy, które broadcastują fragmenty Turbo Stream przez Action Cable. Helper `turbo_stream_from` po stronie klienta subskrybuje odpowiedni strumień. Utworzenie nowej wiadomości automatycznie dołącza jej wyrenderowany partial do DOM każdego podłączonego klienta. Ten wzorzec redukuje funkcjonalności czasu rzeczywistego do deklaracji w modelu i helpera w widoku — bez własnych kanałów, bez handlerów JavaScript, bez ręcznej manipulacji DOM. ## Skalowanie Action Cable na produkcji Wdrożenia produkcyjne wymagają starannego przemyślenia wyboru adaptera, limitów połączeń i skalowania horyzontalnego. ```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 pełni rolę szkieletu pub/sub, zapewniając, że wiadomości opublikowane w jednym procesie Rails docierają do subskrybentów podłączonych do dowolnego innego procesu. Bez Redisa (lub Solid Cable) adapter async ogranicza broadcasting do pojedynczego procesu — co jest nieużyteczne w jakimkolwiek wdrożeniu wieloprocesowym lub wieloserwerowym. Limity połączeń zależą od serwera. Puma z Action Cable obsługuje połączenia WebSocket w tym samym procesie co żądania HTTP. Każdy WebSocket utrzymuje trwałe połączenie, zajmując wątek (lub fiber w Ruby 3.x z planistami opartymi na fiberach). Typowa konfiguracja Pumy z 5 wątkami i 4 workerami może obsłużyć około 200 jednoczesnych połączeń WebSocket przed nasyceniem. Dla aplikacji wymagających tysięcy jednoczesnych połączeń [AnyCable](https://anycable.io/) zastępuje rubowy serwer WebSocket serwerem napisanym w Go, obsługującym połączenia na poziomie protokołu, jednocześnie kierując logikę kanałów z powrotem do Rails przez gRPC. Ta architektura obsługuje ponad 10 000 jednoczesnych połączeń na węzeł. > **Wskazówka na rozmowę** > > Rekruterzy często pytają o limity skalowania Action Cable. Kluczowa odpowiedź: sam Action Cable nie jest wąskim gardłem — jest nim proces Ruby obsługujący połączenia WebSocket. AnyCable rozwiązuje ten problem, przenosząc zarządzanie połączeniami do Go, zachowując logikę kanałów w Ruby. ## Testowanie kanałów Action Cable Rails dostarcza `ActionCable::Channel::TestCase` do testów jednostkowych kanałów oraz `ActionCable::Connection::TestCase` do testowania uwierzytelniania połączeń. ```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 ``` Metoda `stub_connection` konfiguruje kontekst połączenia bez prawdziwego WebSocketa. `assert_has_stream_for` weryfikuje powiązanie ze strumieniem. `assert_broadcast_on` przechwytuje broadcasty w bloku, potwierdzając dostarczenie właściwego payloadu do właściwego strumienia. ## Najczęstsze pytania rekrutacyjne o Action Cable Pytania na rozmowach technicznych dotyczące Action Cable zazwyczaj sprawdzają zrozumienie protokołu, decyzji architektonicznych i problemów produkcyjnych. **Jak Action Cable uwierzytelnia połączenia?** Uwierzytelnianie odbywa się w metodzie `ApplicationCable::Connection#connect` podczas handshaku WebSocket. W tym momencie dostępne są ciasteczka z sesji HTTP. Uwierzytelnianie tokenem przekazuje token jako parametr zapytania w URL WebSocket i waliduje go w `connect`. **Co się dzieje, gdy połączenie WebSocket zostanie zerwane?** Biblioteka kliencka implementuje automatyczne ponowne łączenie z wykładniczym backoffem. Po stronie serwera `unsubscribed` uruchamia się dla każdego kanału, który subskrybowało dane połączenie. Stanowe porządkowanie (oznaczanie użytkowników jako offline, zwalnianie blokad) należy umieszczać w `unsubscribed`. **Kiedy wybrać Solid Cable zamiast Redisa?** Solid Cable sprawdza się w aplikacjach o umiarkowanych potrzebach czasu rzeczywistego (poniżej 100 wiadomości na sekundę), które chcą uniknąć infrastruktury Redis. Redis pozostaje konieczny w scenariuszach o wysokiej przepustowości lub gdy krytyczne jest opóźnienie dostarczenia poniżej 10ms. > **Częsty błąd** > > Umieszczanie logiki autoryzacji w klasie połączenia zamiast w poszczególnych kanałach. Połączenie uwierzytelnia tożsamość (kim jest ten użytkownik?). Kanały autoryzują dostęp (czy ten użytkownik może wejść do tego pokoju?). Mieszanie tych odpowiedzialności tworzy luki bezpieczeństwa. ## Podsumowanie - Action Cable opakowuje protokół WebSocket w konwencje Rails z połączeniami, kanałami i subskrypcjami jako głównymi abstrakcjami - Uwierzytelnianie należy do `ApplicationCable::Connection`; autoryzacja do callbacków `subscribed` w poszczególnych kanałach - Solid Cable w Rails 8 eliminuje zależność od Redisa, wykorzystując bazę danych do pub/sub — odpowiedni dla aplikacji o umiarkowanej przepustowości - Turbo Streams wykorzystują Action Cable do automatycznych aktualizacji DOM w czasie rzeczywistym z minimalną ilością kodu - Skalowanie produkcyjne wymaga Redisa lub Solid Cable do wdrożeń wieloprocesowych; AnyCable obsługuje ponad 10 000 połączeń dzięki przeniesieniu zarządzania WebSocketami do Go - Testowanie kanałów wykorzystuje `stub_connection`, `assert_has_stream_for` i `assert_broadcast_on` — bez potrzeby rzeczywistych połączeń WebSocket - [Przećwicz pytania rekrutacyjne dotyczące Action Cable i WebSocketów](/pl/technologies/ruby-on-rails/interview-questions/action-cable-websockets), aby utrwalić te koncepcje celowanymi ćwiczeniami --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/ruby-on-rails/action-cable-websockets-complete-guide