You are currently viewing Implementing Observer Pattern in Ruby
implementing-observer-pattern-in-ruby

Implementing Observer Pattern in Ruby

  • Post published:June 30, 2016

Software design patterns help to speed up the development process. These have been proven and tested in this field while resolving specific problems in the best possible way. These patterns are abstract solutions that can be mapped in myriad situations and are classified in the following categories:

  • Behavioral patterns
  • Structural patterns
  • Creational patterns
  • Concurrency patterns
    .

Observer pattern falls in behavioral patterns category. As the pattern name “Observer” suggests that part of code will observe something such as temperature, stock value or a new user registration, etc. The subject of the observation is an entity that runs the process to be observed (such as user registration). Whenever something of interest happens, the subject notifies the Observer about the event. The Observer then process the information and take some action.

This post explains how to implement an observer pattern in Ruby. Additionally, it contains ActiveRecord and Mongoid based implementations to give an idea of its working in Ruby on Rails.

Implementation in Ruby

The class name of the ‘observer’ object is generally created by appending the word ‘Observer’ to the class name of the subject for example, UserObserver or StockObserver. Below is an example in which the file that contains code for StockObserver is named as stock_observer.rb.

Adding One Observer

Add the following code in stock.rb file:

#!/usr/bin/ruby
load 'stock_observer.rb'
class Stock
 attr_reader :minimum_quantity_limit, :observer
 attr_accessor :available_quantity#, :observer
 
 def initialize(available_quantity, minimum_quantity_limit)
   @available_quantity = available_quantity
   @minimum_quantity_limit = minimum_quantity_limit
   @observer = StockObserver.new
 end
 
 def update_available_quantity(available_quantity)
   @available_quantity = available_quantity
   notify_observer
 end
 
 private
 def notify_observer
  @observer.notify(self)
 end
 
 s = Stock.new 40,10
 puts s.inspect
 s.update_available_quantity(20)
 s.update_available_quantity(15)
 s.update_available_quantity(10)
 s.update_available_quantity(9)
 s.update_available_quantity(5)
end

Now add the following code in stock_observer.rb file:

class StockObserver
   def notify(stock)
 if stock.available_quantity <= stock.minimum_quantity_limit
   puts "Stock reached minimal limit!  Minimum Quantity Limit: #{stock.minimum_quantity_limit}      Available Quantity: #{stock.available_quantity}"
   #Code to send email to purchase dept
 else
   puts "Available Quantity: #{stock.available_quantity}"
 end
   end
end

The output for stock.rb command will be:

Available Quantity: 20
Available Quantity: 15
Stock reached minimal limit!  Minimum Quantity Limit: 10   Available Quantity: 10
Stock reached minimal limit!  Minimum Quantity Limit: 10   Available Quantity: 9
Stock reached minimal limit!  Minimum Quantity Limit: 10   Available Quantity: 5

In stock.rb file, only one observer has been added.

Adding Multiple Observers

For adding multiple observers in stock.rb file, use the following code:

#!/usr/bin/ruby
load 'stock_observer.rb'
load 'test_observer.rb'
class Stock
 attr_reader :minimum_quantity_limit, :observers
 attr_accessor :available_quantity
 
 def initialize(available_quantity, minimum_quantity_limit)
   @available_quantity = available_quantity
   @minimum_quantity_limit = minimum_quantity_limit
   @observers = []
 end
 
 def update_available_quantity(available_quantity)
   @available_quantity = available_quantity
   notify_observers
 end
 
 def add_observers(*observer_instances)
   observer_instances.each{|observer_instance| observers << observer_instance}
 end

 private
 def notify_observers
   observers.each{|observer| observer.notify(self) }
 end
 
 s=Stock.new 40,10
 s.add_observers(StockObserver.new, TestObserver.new)
 puts s.inspect
 s.update_available_quantity(20)
 s.update_available_quantity(15)
 s.update_available_quantity(10)
 s.update_available_quantity(9)
 s.update_available_quantity(5)
end

The output will be:

Available Quantity: 20
In Test Observer
Available Quantity: 15
In Test Observer
Stock reached minimal limit!  Minimum Quantity Limit: 10   Available Quantity: 10
In Test Observer
Stock reached minimal limit!  Minimum Quantity Limit: 10   Available Quantity: 9
In Test Observer
Stock reached minimal limit!  Minimum Quantity Limit: 10   Available Quantity: 5
In Test Observer

This is how custom observers has been created.

Creating Observers in Rails using ActiveRecord and Mongoid

Ruby on Rails also provides a way to create observers that requires much less code. For writing observers in Ruby on Rails using ActiveRecord, add the following code:

class StockObserver < ActiveRecord::Observer

def after_update(stock)
  if stock.quantity <= stock.minial_limit
  #send email code here
  end    
end
end

In Mongoid, just replace ActiveRecord::Observer with Mongoid::Observer. Rest code will remain the same.

Activation of Observers

In config/application.rb file, you need to register observers. Only registered observers are  activated. This can be done by adding the following line of code to the body of class Application < Rails::Application in file application.rb in case of ActiveRecord:

config.active_record.observers = :stock_observer, :registration_observer

In case of Mongoid, add the following:

config.mongoid.observers = :stock_observer, :registration_observer