35

i thought about using observers or callbacks. What and when you should use an observer?

F.e. you could do following:

# User-model
class User << AR
  after_create :send_greeting!

  def send_greeting!
    UserNotifier.deliver_greeting_message(self)
  end

end

#observer
class UserNotifier << AR
  def greeting_message(user)
  ...
  end
end

or you could create an observer and let it watch when users becomes created...

What dou you recommened?

Ryan Bigg
  • 106,965
  • 23
  • 235
  • 261
BvuRVKyUVlViVIc7
  • 11,641
  • 9
  • 59
  • 111

3 Answers3

45

One really important distinction to keep in mind, which is related to Milan Novota's answer, is that callbacks on an ActiveRecord have the ability to cancel the action being called and all subsequent callbacks, where as observers do not.

class Model < ActiveRecord::Base
  before_update :disallow_bob

  def disallow_bob
  return false if model.name == "bob"
  end
end

class ModelObserver < ActiveRecord::Observer
  def before_update(model)
    return false if model.name == "mary"
  end
end

m = Model.create(:name => "whatever")

m.update_attributes(:name => "bob")
=> false -- name will still be "whatever" in database

m.update_attributes(:name => "mary")
=> true -- name will be "mary" in database

Observers may only observe, they may not intervene.

Michael Johnston
  • 5,298
  • 1
  • 29
  • 37
  • 19
    This is no longer the case in rails 3.1 observers can cancel the action of a save by returning false from the before_* which will cancel the action and may also raise an exception in after_* to cancel the action exceptionally. – Joel Wickard Dec 20 '11 at 14:31
  • Thanks jrizza, i had a similar case wherein a failure in one of the observers caused the record not to save, which i think is an undesirable outcome. – Pratik Khadloya Mar 12 '12 at 17:15
  • 2
    Yes it's strange, they are no longer observers, an exception in an observer will cause the commit to fail and user gets an exception screen. Doesn't make sense to me. – Amala Sep 14 '12 at 22:53
30

You can use observers as a means of decoupling or distribution of responsibility. In the basic sense - if your model code gets too messy start to think about using observers for some unessential behavior. The real power (at least as I see it) of observers lies in their ability to serve as a connection point between your models and some other subsystem whose functionality is used by all (or some) of the other classes. Let's say you decide to add an IM notification to your application - say you want to be notified about some (or all) of the CRUD actions of some (or all) of the models in your system. In this case using observers would be ideal - your notification subsystem will stay perfectly separated from your business logic and your models won't be cluttered with behavior which is not of their business. Another good use case for observers would be an auditing subsystem.

Milan Novota
  • 15,506
  • 7
  • 54
  • 62
14

A callback is more short lived: You pass it into a function to be called once. It's part of the API in that you usually can't call the function without also passing a callback. This concept is tightly coupled with what the function does. Usually, you can only pass a single callback..

Example: Running a thread and giving a callback that is called when the thread terminates.

An observer lives longer and it can be attached/detached at any time. There can be many observers for the same thing and they can have different lifetimes.

Example: Showing values from a model in a UI and updating the model from user input.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820