Read my latest article: Planet Argon Blog (posted Wed, 17 Feb 2010 15:11:00 GMT)

Observers Big and Small

Posted by Robby Russell Fri, 27 Apr 2007 18:15:00 GMT

10 comments Latest by Blackjack virtuale Fri, 19 Feb 2010 07:28:56 GMT

My colleague, Gary, keeps a stack of Ruby and Rails books on his desk and was implementing an Observer into a client project. It appears that the Agile Web Development with Rails book is still encouraging people to do the following in order to load an Observer.


# app/models/flower_observer.rb
class FlowerObserver < ActiveRecord::Observer
  observe Flower

  def after_create(model)
    # model.do_something!
  end
end

# controller(s)
class FlowerController < ApplicationController
  observer :flower_observer
end

What is wrong with this approach?

Well, in order for your Observer to be used, the model(s) callbacks that it is observing need to be triggered through a controller. If you end up writing any scheduled rake tasks, your observer will not be called. In my opinion, the controller shouldn’t know this much about the model. In fact, the model doesn’t even really know about it’s observer… so why should a controller?

This was actually changed a long time ago (I previously blogged about a different solution here) and the Rails docs for ActiveRecord::Observer are currently correct.

Observers in the Environment

If you open up a recent version of config/environment.rb, you notice in the comments the following.


  # Activate observers that should always be running
  # config.active_record.observers = :cacher, :garbage_collector

Take a moment to go ahead and specify which observer(s) you’d like to load into your Rails environment.

config.active_record.observers = :flower_observer

Then you can remove your observer calls in all your controllers, because that’s not where you should be defining them.

Also, if you’re not using Observers yet, I’d really encourage you to consider reading up on them and giving them a try.

Subscribe to my RSS feed Enjoying the content? Be sure to subscribe to my RSS feed.
Comments

Leave a response

  1. Avatar
    Matt King Fri, 27 Apr 2007 18:51:55 GMT

    This is great to know. I’ve used observers before, mostly in the context of caching views, but not for observing events in models. It seems to me that if you have more than one before_[whatever] or after_[whatever] in your model it’s probably best to move them into an observer. I have a few models that have a ton of these callbacks that will be nice to move out into another location. Thanks!

  2. Avatar
    Eric A. Fri, 27 Apr 2007 18:52:13 GMT

    Why not just use ActiveRecord callback hooks instead of Observers? Are Observers more powerful or is it just a matter of preference?

  3. Avatar
    Adam R. Fri, 27 Apr 2007 23:02:24 GMT

    Yeah, I’d like to know the benefits too. Can you shed some light on this Robby?

    (I’d also like the ability to use the logger from within an observer, but that’s another issue)

  4. Avatar
    Alain Ravet Sun, 29 Apr 2007 07:40:40 GMT

    Eric A

    > Why not just use ActiveRecord callback hooks instead of Observers?
    2 rules of thumb:
    • if a model could become invalid should the triggered action not take place, use AR hooks.
    • if the triggered action modifies the model (ex: pre-render and cache textile text in the model), use AR hooks.

    Otherwise use/consider observers.

  5. Avatar
    sjs Sun, 29 Apr 2007 18:59:26 GMT

    Creating a new record may be cause for some action to be triggered. If that action is tangential to the model which triggers it then it makes sense to keep that action separate. The AR docs have some logical examples that should help you see the point of using observers.

    Observers use the same AR callbacks. You don’t use observers as a replacement for AR callbacks; observers augment the usefulness of the AR callbacks.

  6. Avatar
    Robby Russell Mon, 30 Apr 2007 00:19:36 GMT Recommend me on Working with Rails

    Thanks for the comments!

    I’ve posted a follow up to this article with responses to some of our questions.

  7. Avatar
    Michael Hendrickx Fri, 07 Aug 2009 14:56:43 GMT

    Do observers “block” the rendering?

    If you have a timely job to be done upon a model.save, would it pause the rendering until it is done?

    I am implementing a module that will email a comment, but this will go to a few 100 people. I don’t want the submitter to wait for minutes while this is happening.

    Thank you, Michael

  8. Avatar
    Robby Russell Sat, 08 Aug 2009 20:41:22 GMT Recommend me on Working with Rails

    Michael,

    Yes, it’d be part of the request/response cycle. You could pass it off via Ajax or delegate to a background task (bj?)

  9. Avatar
    Gordon Yeong Tue, 19 Jan 2010 22:43:46 GMT

    hi, there :) and http://api.rubyonrails.org//

    Good post :)
    I refered to http://guides.rubyonrails.org/action_mailer_basics.html

    I am a bit unclear about observers.

    Consider the set up below:

    model/part_mailer.rb —-—-—-—-—-- class PartMailer < ActionMailer::Base @admin_email = ‘admin@sample.com’ @from_email = ‘admin-sales@sample.com

    def created_succesfully(part)
      recipients user.email, @admin_email
      from @from_email
      subject "MyApp - New part created." 
      body :user => user
    end

    model/part_observer.rb —-—-—-—-—-——

    class PartObserver < ActiveRecord::Observer def after_create(part) PartMailer.deliver_created_succesfully(part) end end

    It looks as if I can only pass in the object of the given class into the observer. In the case above, ‘part’ is the only one that is being passed by to deliver_created_successfully in model/part_observer.rb. part_mailer.rb)? I tried looking at the api docs and http://guides.rubyonrails.org/action_mailer_basics.html to no success. Can someone please shed some light into this?

    Can I pass more objects to the method, created_successfully (model/

    Thanks! :)

  10. Avatar
    Blackjack virtuale Fri, 19 Feb 2010 07:28:56 GMT

    I have a minor css issue and wonder if someone sees something obvious. This menu looks good in FireFox and IE7 but in IE8, unless I use compatibility mode, the menu li renders odd – double bullets or the link is below and right of the li. I’m not sure if this is IE8’s problem or the structure I have here.

Share your thoughts... (really...I want to hear them)

Comments