Observational: Better Observers for ActiveRecord


Aug 05, 2009

This sort of thing appears in just about every rails app I've ever worked on:

class User
  after_create :send_welcome_email

  protected
    def send_welcome_email
      Notifier.deliver_welcome_email(self)
    end
end

Why would the user have to ask the notifier to send him his own welcome message? That seems like the Notifier's responsibility, if you ask me.

Using an ActiveRecord observer, we can absolve the user of that responsibility. That code would look something like this:

class UserObserver < ActiveRecord::Observer
  def after_create(user)
    Notifier.deliver_welcome_email(user)
  end
end

Note that you'd also have to activate this observer in config/environment.rb.

In some ways, using an observer is better than putting a callback in the User model. It's definitely a better division of responsibilities. But, it feels a little cumbersome.

In the rails app where I spend most of my time, we currently use callbacks to trigger over a dozen mailers, and almost 50 types of activity feed items. So, we'd need a lot of observer subclasses.

A Better Way

The observer pattern, in some form, seemed like the right approach. I wanted to find a way to use it without creating eleventy billion observer classes.

I came up with a gem that I call observational. Here's what it looks like:

class Notifier < ActionMailer::Base
  observes :user, :after => :create, :invokes => :deliver_welcome_email

  def welcome_email(user)
  end
end

This example is functionally equivalent to the first example above. Notifier.deliver_welcome_email will be called during the after_create callback of any User object, with the user object as the first and only argument.

Observational supports any standard ActiveRecord callback. As far as I know, anything you can do with a standard AR observer, you can do with observational. Let me know if I'm wrong about that.

Get It!

sudo gem install giraffesoft-observational

Fork it at github.

Or read the yardoc at rdoc.info.