Yesterday, I wrote a short post titled, Observers Big and
Small,
about using Observers in your Rails applications.
The following questions were raised in the comments.
When should I use an Observer?
Eric Allam asks…
“Why not just use ActiveRecord callback hooks instead of Observers?
Are Observers more powerful or is it just a matter of preference?”
Eric, this is an excellent question. I’d say that a majority of the
time, using the ActiveRecord
callbacks
in your models is going to work for your situation. However, there are
times that you want the same methods to be called through callbacks. For
example, let’s take a recent problem that we used an observer to solve.
Graeme is working on implementing
Ferret into a project that we’re
developing for a client. With the use of Ferret, we can index and later
search through content over several objects into a format that makes
sense for our implementation goals. Each time an object is created and
updated, we have to update our Ferret indexes to reflect these changes.
The most obvious location that we can call our indexing methods is in
each models’ callbacks, but this violates the DRY principle. So, we created an Observer,
which observes each of the models that need these methods to be
called. In fact, as far as we’re concerned, the fact that we’re indexing
some of its data, is none of its business. We only want our models to be
concerned with that they’re designed to be concerned about. We may opt
to change our indexing solution in the future and we’d just need to
rethink that at the Observer level and not change anything about the
business logic in our models.
This is the sort of scenario when using an Observer makes great sense in
your application.
Logging from an Observer
Adam R. asks…
“I’d also like the ability to use the logger from within an observer,
but that’s another issue.”
I assume that you are referring to the logger
method? I always forget
to even use that method. I do know that the following works just fine in
an Observer.
class IndexObserver < ActiveRecord::Observer
observer Article, Editorial, BlogPost, ClassifiedAd
def after_save(model)
RAILS_DEFAULT_LOGGER.warn("Every single day. Every word you say. Every game you play. Every night you stay. I'll be watching you.")
# execute something fun
end
end
This will output to your log file without any problem.
This reminded me of when I used to want to log from Unit
Tests.
(few minutes later)
Okay, I just attempted to use logger
from an Observer and you’re
right… it doesn’t currently work. There is a simple fix though, just
extend ActiveRecord::Observer to add a logger
method like so and
require it in config/environment.rb
(much like I did in with unit
tests).
# lib/observer_extensions.rb
class ActiveRecord::Observer
def logger
RAILS_DEFAULT_LOGGER
end
end
This will give you a solution to that problem.
class FooObserver < ActiveRecord::Observer
observer Foo
def after_save(model)
logger.warn("I wonder if the #{address.class} knows that I've been watching it all along?")
end
end
Observers Spy for Us
Most often, I look at Observers as being the guys that I hire to spy on
my models. I don’t want my models to know that they’re being spied on
and I’d like to keep it that way. They don’t solve all of our problems
and it’s easy to overuse them. However, I have found several cases that
they made a lot of sense and most of those cases have been where we’ve
had the same things occurring in our model’s callbacks.
If you have other questions related to Observers, feel free to let me
know. If you’re already using Observers, perhaps you could post a
comment and/or blog post response with an example of when and how you
use Observers in your Rails applications.
Related Posts