Introduction
Broadcasting is how your Rails application pushes data to connected clients. The power of Action Cable lies in the fact that you can broadcast from anywhere in your codebase — controllers, models, background jobs, or even the Rails console. Understanding where and how to broadcast is key to building responsive real-time features.
Key Concepts
broadcast_to: A class method on channels that sends data to all subscribers of a stream derived from a model. It pairs withstream_forin the channel.ActionCable.server.broadcast: A lower-level method that broadcasts to a raw stream name. It pairs withstream_fromin the channel.- Broadcasting from Jobs: The recommended pattern for heavy operations — broadcast the result from a background job to avoid blocking the request cycle.
- Global Broadcasting: Any code with access to the
ActionCable.serverobject can broadcast, including rake tasks, console sessions, and service objects.
Real World Context
In a project management app, when a user creates a task, the controller saves it to the database and enqueues a background job. The job processes the task (sends emails, updates counters), then broadcasts the new task to all team members viewing the board. This decouples the HTTP response from the real-time update, keeping both fast.
Deep Dive
The most common way to broadcast is using broadcast_to on a channel class:
ruby# From a controller class MessagesController < ApplicationController def create @room = Room.find(params[:room_id]) @message = @room.messages.create!(message_params.merge(user: current_user)) # Broadcast to all subscribers of ChatChannel for this room ChatChannel.broadcast_to(@room, { type: "new_message", id: @message.id, user: current_user.username, body: @message.body, created_at: @message.created_at.iso8601 }) head :created end end
ChatChannel.broadcast_to(@room, data) generates the same stream name that stream_for @room uses inside the channel, ensuring the data reaches the right subscribers.
For broadcasting from a background job:
ruby# app/jobs/notification_broadcast_job.rb class NotificationBroadcastJob < ApplicationJob queue_as :default def perform(notification) NotificationsChannel.broadcast_to( notification.user, { type: "notification", id: notification.id, title: notification.title, body: notification.body, read: false, created_at: notification.created_at.iso8601 } ) end end
Trigger this from a model callback or service object:
ruby# app/models/notification.rb class Notification < ApplicationRecord after_create_commit -> { NotificationBroadcastJob.perform_later(self) } end
Using after_create_commit ensures the broadcast only fires after the database transaction commits, so subscribers always see consistent data.
You can also broadcast from the Rails console for debugging:
ruby# In rails console user = User.find(1) NotificationsChannel.broadcast_to(user, { type: "test", message: "Hello from console!" })
For raw stream names (when using stream_from instead of stream_for):
rubyActionCable.server.broadcast("chat_room_general", { user: "System", body: "Welcome to the general channel!" })
Common Pitfalls
- Broadcasting before the transaction commits — Using
after_createinstead ofafter_create_commitcan broadcast data that gets rolled back if the transaction fails. Always use the_commitvariants. - Broadcasting large payloads — Sending entire ActiveRecord objects or deeply nested associations through WebSockets wastes bandwidth and can expose sensitive attributes. Serialize only the fields the client needs.
- Blocking the request cycle with broadcasts — If broadcasting involves any I/O (like fetching additional data), move it to a background job. The HTTP response should not wait for the broadcast to complete.
Best Practices
- Use
after_create_commitfor model-triggered broadcasts — This ensures data consistency by broadcasting only after the database transaction has committed. - Move complex broadcasts to background jobs — Keep controllers and model callbacks thin. Jobs can safely perform additional queries or formatting.
- Include a
typefield in every broadcast payload — This lets the client-sidereceivedcallback route messages to the correct handler.
Summary
broadcast_to(model, data)sends data to all subscribers of the stream derived from the model.- Broadcasting works from controllers, models, background jobs, services, and even the Rails console.
- Always use
after_create_commit(notafter_create) to avoid broadcasting uncommitted data. - Move heavy broadcast logic to background jobs to keep the request cycle fast.
- Serialize only the fields the client needs — never broadcast entire ActiveRecord objects.
Code Examples
# Broadcasting from a model callback via a background job
class Notification < ApplicationRecord
after_create_commit -> { NotificationBroadcastJob.perform_later(self) }
end
# app/jobs/notification_broadcast_job.rb
class NotificationBroadcastJob < ApplicationJob
def perform(notification)
NotificationsChannel.broadcast_to(
notification.user,
{ type: "notification", title: notification.title }
)
end
end