Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

  • Blog Navigation
Introducing ActiveModelListener: Easy to use global ActiveRecord event listeners

I’m currently working on a large app where certain things have to happen when records are created, updated and deleted, such as:

  • Publishing to an activity feed
  • Generating emails
  • Adding entries to a changelog
  • Generating tasks and reminders

Further, the requirements state that admin users should be able to configure which of these actions happen for which objects in the system, who they go to, what the text is etc…

At first this looks like a great place for ActiveRecord Observers. However, after working with Observers there are a few things I dislike – namely that you can’t easily apply observers to all of your models, and you can’t selectively turn them on and off in tests. To remedy that problem, I created ActiveModelListener.

ActiveModelListener is a simple, global ActiveRecord event listener framework, using a middleware-esque architecture that can easily be turned on and off.


sudo gem install gemcutter
sudo gem tumble
sudo gem install active_model_listener


First, require active_model_listener above your rails initializer in environment.rb:

# environment.rb
require 'active_model_listener' do |config|
  # ...

Next, add the listeners you’d like to apply (in order) to the ActiveModelListener in an initializer:

# config/initializers/active_model_listener.rb
ActiveModelListener.listeners << ActivityFeedListener

Then, create a listener class that defines methods for after_create, after_update and / or after_destroy, like so:

class ActivityFeedListener
  class << self
    def after_create(record)
      description = "#{} was created"
      publish_activity_feed_items record, description

    def after_update(record)
      description = "#{} was updated"
      publish_activity_feed_items record, description

    def after_destroy(record)
      description = "#{} was deleted"
      publish_activity_feed_items record, description

    def publish_activity_feed_items(record, description)
      record.activity_feed_item_subscribers.each do |subscriber|
        ActivityFeedItem.create :user => subscriber, :description => description

    private :publish_activity_feed_items

Notice how the class looks almost identical to an ActiveRecord observer, so you can easily refactor between the two.

Turning off listeners in specs

When unit testing if your listeners are all firing your unit tests become integration tests. To avoid this, you can easily turn off listeners for all specs all the time:

Spec::Runner.configure do |config|
  config.before(:each) do

Then, when you want them back on again, you can turn them back on for a spec:

describe "Integrating with listeners" do
  before do
    ActiveModelListener.listeners << FooListener

Specifying a subset of listeners to use

When doing data imports, migrations or certain actions that need to only use certain listeners, you can easily specify which ones you’d like to use:

ActiveModelListener.with_listeners AuditListener, ActivityListener do
  Article.create! :title => "foo"

After the block runs, the original listeners are restored.

If you want to run some code with no listeners at all, you can do so with:

ActiveModelListener.without_listeners do
  Article.create! :title => "foo"


  • Chad Woolley

    It’s situations like this where I miss the power of [Aspect-Oriented Programming]( in Java. You could hang logic off of any method, anywhere, with fine-grained control over pointcuts.

  • Peter Jaros

    I’m out for *one day* and you guys write an entire event listening framework.


  • I’ve been thinking about this same problem, but I’d need a solution more closely coupled with the controller- so I can have access to things like @current_user in my listener. Might be some clever workaround though. Hmm.

  • Jeff Dean

    @jason – Having tried to do this at the controller level, I don’t recommend it :-P At the risk of starting another flamewar from MVC purists, here’s what has worked for me. In ApplicationController:

    before_filter :set_current_user_from_session

    def set_current_user_from_session
    User.current_user = current_user

    Once User.current_user is set, I have access to it from all of my models, and Switchboard allows me to add the acting user’s id to audit tables. There are several other ways to skin that cat (explicitly adding :acting_user, :current_user params etc.. to each model instantiation is one), but the example above has worked for me in all of my apps.

    In any case, all you have to do is get some notion of the acting user into your model, and Switchboard / Observers / custom callbacks can all reference it.

  • Peter Jaros

    @jeff, jason: Just make sure that `User.current_user=` is backed by a thread-local variable and not a class variable if you want thread safety.

  • I’m pretty sure I’ve used `observe ActiveRecord::Base` inside of an observer to make it listen to all of my models. The ability to turn them off in tests is pretty cool though. Nice work.

  • Jeff Dean

    For anyone looking for this gem or code, it’s currently down on github. I’ve got a ticket in and hopefully it will be up soon.

    Thanks to all of those who have chosen to follow it, even though you can’t see it!

Share This