ProblemYou want to execute some code at some stage in the life cycle of an Active Record object. For example, each time a new object is created, you want to be notified with an email containing the details of that object. Because this code may not have anything to do with the logic defined by the model, you'd like to keep it elsewhere. This way, the model and code being invoked are decoupled and hence, more flexible. SolutionUsing Active Record observer classes, you can define logic outside of your model classes that will be called during the life cycle of Active Record objects. Suppose you have an application that stores subscriptions to some service. The subscriptions table is defined by the following migration: db/migrate/001_create_subscriptions.rb: class CreateSubscriptions < ActiveRecord::Migration def self.up create_table :subscriptions do |t| t.column :first_name, :string t.column :last_name, :string t.column :email, :string end end def self.down drop_table :subscriptions end end The Subscription model may contain logic specific to the data it contains, such as validation or customized accessors: app/models/subscription.rb: class Subscription < ActiveRecord::Base # model specific logic... end First, create an observer for the Subscription model. In the models directory, create a class named after the Subscriptions model. This class must implement the after_create Active Record callback method. app/models/subscription_observer.rb: class SubscriptionObserver < ActiveRecord::Observer def after_create(subscription) 'echo "A new subscription has been created (id=#{subscription.id})" | mail -s 'New Subscription!' recipient@example.com' end end Previous versions of Rails (prior to Rails 1.2) required that you link the SubscriptionsObserver to the Subscriptions model with a call to the observer method in the controller. This is no longer necessary, but you do have to register your observer(s) in your environment.rb file: config/environment.rb: Rails::Initializer.run do |config| #... config.active_record.observers = :subscription_observer end DiscussionThe SubscriptionsObserver defined by the solution is triggered right after every new subscription object is created. The after_create method in the observer simply calls the system's mail command, sending notice of a new subscription. The following is a list of active record callback methods that can be defined in an observer:
By providing implementations for these callbacks, you can integrate external code into any part of the changing state of your model objects. If your observer's class name does not follow the convention of being named after the model it is supposed to observe, you can explicitly declare it with the observe method. For example, the following sets up the SubscriptionObserver class to observe an Accounts model: class SubscriptionObserver < ActiveRecord::Observer observe Account def after_update(record) # do something... end end Specify more than one model by passing several (comma separated) to the observe method. See Also
|