Let ActiveRecord Observers See Controller Context

You might be thinking, “does this break MVC?” Well, I don’t know. And honestly, I don’t care. I find it useful to sometimes be able to access stuff that was available in the controller at the time my observer was invoked (like the session object).

So I wrote a small module called EnlightenObservers.

EnlightenObservers is a controller module that will give your ActiveRecord::Observer objects the ability to see the controller context in which they were called.

To use EnlightenObservers, perform the following in your controller:

  1. include EnlightenObservers
  2. Instantiate your observers using the observer() method

For example:

1
2
3
4
5
class MyController < ActionController::Base
  include EnlightenObservers

  observer :my_observer
end

Step #2 is important because one of the more common ways to instantiate observers is to include them in your environment.rb, and doing so will cause no errors, but this module will not “turn on” if you do so. So don’t forget this step.

Now, in your Observer, you may use the name “controller” to access the controller, just like in a view or CacheSweeper.

Here’s the module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
module EnlightenObservers
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def observer(*observers)
      super

      configuration = observers.last.is_a?(Hash) ? observers.pop : {}
      observers.each do |observer|
        observer_instance = Object.const_get(Inflector.classify(observer)).instance
        class <<observer_instance
          include Enlightenment
        end

        around_filter(observer_instance, :only => configuration[:only])
      end
    end
  end

  module Enlightenment
    def self.included(base)
      base.module_eval do
        attr_accessor :controller
      end
    end

    def before(controller)
      self.controller = controller
    end

    def after(controller)
      self.controller = nil # Clean up for GC
    end
  end
end

This code is MIT / X11 licensed, have a ball.

Comments