Paulo Silva

March 14, 2025

Building a Chat Feature in Ruby on Rails with Pusher

Adding a chat feature to a marketplace or platform can significantly improve user engagement. Recently, I built a chat system that allows B2C users to communicate with B2B merchants through a Ruby on Rails API, with real-time notifications powered by Pusher. Here’s how I did it.


Data Model

The core of the chat feature consists of two main models:

  1. ChatRoom: Represents a unique conversation between a user and a listing.
  2. ChatMessage: Represents individual messages within a chat room.

Since messages can be sent by either users or merchants, the ChatMessage model uses a polymorphic association for the sender and receiver.


ChatRoom Model

class ChatRoom < ApplicationRecord
  belongs_to :user
  belongs_to :listing

  has_many :chat_messages, dependent: :destroy
end


Each chat room is unique to a user and a listing, ensuring that a user doesn’t have multiple chat threads for the same listing.


ChatMessage Model

class ChatMessage < ApplicationRecord
  belongs_to :chat_room
  belongs_to :sender, polymorphic: true
  belongs_to :receiver, polymorphic: true

  after_create_commit :send_realtime_notification
end


This setup allows for flexibility in sending messages from both sides—whether from a user to a merchant or vice versa.


Real-Time Notifications with Pusher

To ensure instant message updates, I integrated Pusher. When a new message is created, it triggers a real-time event.

Broadcasting Messages
In the ChatMessage model:

def send_realtime_notification
  Pusher.trigger("chat_#{chat_room.id}", "new_message", {
    message: self.content,
    sender_id: self.sender_id,
    receiver_id: self.receiver_id
  })
end


Each chat room has its own Pusher channel, ensuring that only relevant participants receive notifications.


API Endpoints

Here’s a basic controller to handle chat messages:

class ChatMessagesController < ApplicationController
  before_action :set_chat_room

  def create
    message = @chat_room.chat_messages.create!(message_params)
    render json: message
  end

  private

  def set_chat_room
    @chat_room = ChatRoom.find(params[:chat_room_id])
  end

  def message_params
    params.require(:chat_message).permit(:content, :sender_id, :sender_type, :receiver_id, :receiver_type)
  end
end


This allows clients (mobile apps) to send messages by making a POST request to the API.


Conclusion

By structuring the data model with ChatRoom and ChatMessage, using polymorphic associations, and integrating Pusher for real-time notifications, I was able to build a flexible chat system that works seamlessly for both B2C users and B2B merchants.

About Paulo Silva

Software Engineer specialized in product development with Ruby on Rails. I help companies turn bright ideas into amazing digital products — I've worked on InvoiceXpress, ClanHR, Today and currently sheerME.