Ruby on Rails (Rails, RoR) is a well-known web application framework written in the Ruby programming language. Pub/Sub is a short name of software design patterns called Publish–subscribe. I’ll explain how communication between software components in Rails could be handled by Pub/Sub.

What is Pub/sub?

Pub/sub is a software design pattern providing service-to-service communication. Service
entails one of the two roles: publisher (who produce) or receiver (who consumes). What is
produced to be consumed is determined as an event or a message or a notification. In the
context of this article, they are used interchangeably to refer to the same thing.
The service which produces doesn’t know who consumes. The service which consumes doesn’t
know the origin of the message. They can remain unknown to each other. It is different from
message queues, where the component that sends the message often knows its destination
– this style of messaging allows you to send messages anywhere. This mechanism is a core
of Pub/sub and it means that they are decoupled.

To express their mutual interests, they must share a common understanding. Therefore,
both roles have an implicit mechanism of the stick where the producer of a message and the
consumer of the message meet. This mechanism is called subject, subscription or topic. It is
responsible for categorizing messages to subjects, it is essentially a stateless message filter.
Topics act as broadcast stations. A publisher produces the message to the topic,
subscribers immediately receive the message from the topic. Because of decoupled
services, the most efficient way of exchanging messages is to handle them asynchronously.

Rails without Pub/Sub

By default, there is no Rails overhead for software design patterns for passing messages between components. Developers use standard object-oriented programming (OOP) paradigm: passing parameters to functions, asking for classes about values.

When the application is rather uncomplicated, it could be enough. When the application grows, for instance, some operations need to be done asynchronously, then the project needs abstraction which resolves that data workflow. Instead of reinventing the wheel, developers can implement Pub/sub to fill this lack of abstraction.

Pros of Pub/Sub with Rails

Cons of Pub/Sub with Rails

Rails Pub/Sub introduce

Examples of source in Rails was written using library
Pub/Sub on Rails (in Ruby’s nomenclature, a library is called gem): You will find more details in the gem’s readme. Implementation is composed of modules:

  1. Domain,
  2. Event,
  3. Event handler,
  4. Event publisher,
  5. Subscription.

Domain

Describes business logic in order to provide context for Pub/Sub and, therefore, make clean code.

 module Notifications
   extend PubSub::Domain
 end
 module Reports
   extend PubSub::Domain
 end

Event

It is a class which describes what happened. Declare the class name as self-describing with what happened as possible, for example: cancelled, changed, created, destroyed, sent, updated. Event names can look like: ProfitAndLossStatementCreatedEvent, which means that a financial statement was created.

 class Reports::ProfitAndLossStatementCreatedEvent < PubSub::DomainEvent
   attribute :profit_and_loss_statement_id, Types::Strict::Integer
 end

Event publisher

Class capable of emitting events. The example shows creating a service report. When the report was successfully created, emit the event of creating that report.

class Reports::ProfitAndLossStatementService
   include PubSub::Emit
    def execute
     emit(:report_profit_and_loss_statement_created, profit_and_loss_statement_id: id) if result.ok?
   end
 end

Event handler

This class should be executed in response to handling an event.

module Notifications
 class ReportsProfitAndLossStatementCreatedHandler < PubSub::DomainEventHandler
   def call
     ReportMailer.profit_and_loss_statement(profit_and_loss_statement).deliver_now
   end

   private

   def profit_and_loss_statement
     ProfitAndLossStatement.find(event_data.profit_and_loss_statement_id)
   end
 end
end

Subscription

Events are bonded to their handlers through subscriptions.

notifications:
 reports__profit_and_loss_statement_created: async

Example use cases:

Similar patterns

  1. EventBus – components can send events to EventBus without knowing who will pick them up or how many respondents will react,
  2. Observer – the subject maintains a list of dependents, called observers, and notifies them whenever their state changes,
  3. Pooling – when polling, clients periodically ask the system whether there are any new events or data.

Gems

Summary

Pub/sub is not a common approach in Ruby in Rails. As introduced in the article, this pattern can bring many benefits to the project – it can make the code clean, decouple services and make them easily scalable.

cooperation banner
en_USEnglish