DEV Community

Afaq Shahid Khan
Afaq Shahid Khan

Posted on

Understanding Observers in Ruby on Rails

As your Ruby on Rails application grows, maintaining clean and manageable code becomes increasingly important. One of the powerful yet often underutilized features in Rails is the Observer pattern. Observers allow you to keep your models lean by extracting responsibilities that don't necessarily belong in the model itself. In this article, we'll explore what observers are, when to use them, and how to implement them in your Rails application.

What are Observers?

Observers in Rails provide a way to respond to lifecycle callbacks outside of your models. They allow you to encapsulate the callback logic in a separate class, promoting cleaner and more modular code. Observers listen for changes to an object and respond to those changes without the object needing to explicitly notify the observer.

When to Use Observers

Observers are ideal for situations where you want to decouple the callback logic from your models. Here are a few common use cases:

  1. Logging and Analytics: Track changes or actions performed on a model without cluttering the model code.
  2. Notifications: Send emails, Slack messages, or other notifications when certain model events occur.
  3. Asynchronous Jobs: Enqueue background jobs in response to model changes.
  4. Complex Business Logic: Implement business rules that should be applied after certain model changes.

Implementing Observers in Rails

Rails observers are not included in Rails by default anymore, starting from Rails 4. However, you can still use them by including the rails-observers gem in your Gemfile:

gem 'rails-observers'
Enter fullscreen mode Exit fullscreen mode

After adding the gem, run bundle install to install it.

Creating an Observer

Let’s walk through an example of creating an observer. Imagine you have a User model and you want to send a welcome email whenever a new user is created.

  1. Generate the Observer:

First, generate the observer file:

   rails generate observer User
Enter fullscreen mode Exit fullscreen mode

This will create a file app/models/user_observer.rb.

  1. Define the Observer:

Open the generated user_observer.rb file and define the callback methods:

   class UserObserver < ActiveRecord::Observer
     def after_create(user)
       UserMailer.welcome_email(user).deliver_later
     end
   end
Enter fullscreen mode Exit fullscreen mode

Here, after_create is a callback method that will be triggered after a new user is created. The UserMailer.welcome_email(user).deliver_later line enqueues the welcome email to be sent asynchronously.

  1. Register the Observer:

To make Rails aware of the observer, you need to register it. Open config/application.rb and add the following line inside the class Application < Rails::Application block:

   config.active_record.observers = :user_observer
Enter fullscreen mode Exit fullscreen mode
  1. Create the Mailer:

If you haven't already, generate the mailer:

   rails generate mailer UserMailer
Enter fullscreen mode Exit fullscreen mode

Define the welcome_email method in app/mailers/user_mailer.rb:

   class UserMailer < ApplicationMailer
     def welcome_email(user)
       @user = user
       mail(to: @user.email, subject: 'Welcome to My Awesome Site')
     end
   end
Enter fullscreen mode Exit fullscreen mode

Also, create a view template for the email in app/views/user_mailer/welcome_email.html.erb.

Benefits of Using Observers

  • Separation of Concerns: By moving callback logic to observers, your models remain focused on their primary responsibility: data persistence and validation.
  • Reusability: Observers can be reused across different models, promoting DRY (Don't Repeat Yourself) principles.
  • Maintainability: With a clean separation of callback logic, your codebase becomes easier to maintain and understand.

Conclusion

Observers are a powerful tool in the Rails ecosystem for maintaining clean and modular code. By decoupling callback logic from your models, you can achieve a more maintainable and scalable codebase. While Rails no longer includes observers by default, the rails-observers gem makes it easy to integrate this pattern into your application. Use observers to handle logging, notifications, complex business logic, and more, ensuring your models remain lean and focused on their primary responsibilities.

Happy coding!

Top comments (3)

Collapse
 
zaparka profile image
Petr Zaparka

Hi Afar, so I think this might be little controversial. The reason why the observers were taken out from Rails 4 was that it made code hard to read/debug. I remember using them but the app become messy overtime. Maybe that's reason why the gem itself is not maintained since 2017? I do like the idea but there are other ways how to achieve the functionality without making code less readable.

Collapse
 
afaq_shahid profile image
Afaq Shahid Khan

Thanks for your valuable feedback, yes you are right we are using callbacks now.

Collapse
 
htaidirt profile image
Hassen

Hi Petr,

I never used Observers so the idea of using them looked interesting. But I understand that it adds a layer of complexity (in term of readability).

What are the others ways to unclutter business logic you mentionned, without relying on observers?