Terrible Blog

Because Terrible Labs loves you.

Optional Observers With Rails 3 and RSpec

| Comments

Rails observers are great for dealing with side-effects of changes to your models. Unfortunately these side-effects can be both confusing and slow. When doing TDD/BDD, isolation is king and speed is crucial. Disabling observers in unit tests is a must but you’ll want them enabled for integration tests. What’s a tester to do?

Until Rails 3, Pat Maddox’s no-peeping-toms gem was the hotness for disabling observers. It provided an easy syntax to disable observers and enable them as-needed. Bad news: the gem is no longer maintained and works poorly with current versions of Rails. Good news: you don’t need it anymore. ActiveRecord now provides an easy way to turn observers off and on.

Here’s my current approach to this problem in RSpec:

spec/support/observers.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
RSpec.configure do |config|
  config.before do
    # disable all the observers
    ActiveRecord::Base.observers.disable :all

    # find out which observers this spec needs
    observers = example.metadata[:observer] || example.metadata[:observers]

    # turn on observers as needed
    if observers
      ActiveRecord::Base.observers.enable *observers
    end
  end
end

The advantage this approach has over others I’ve seen is that it allows you to simply opt-in to using any number of observers by specifying them in tags on your spec. Here are some example usages:

1
2
3
4
5
6
7
it "does something", observer: :user_observer do
  # ...
end

it "does entirely too much", observers: [:user_observer, :comment_observer] do
  # ...
end

Here are a couple other suggestions for solving this problem:

Thanks to Jeremy Weiskotten for helping me think through this approach.

Any thoughts on this solution? How do you deal with observers in your test suite?

Comments