Recipe 3.15. Performing a Task Whenever a Model Object Is Created


Problem

You 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.

Solution

Using 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

Discussion

The 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:

  • after_create

  • after_destroy

  • after_save

  • after_update

  • after_validation

  • after_validation_on_create

  • after_validation_on_update

  • before_create

  • before_destroy

  • before_save

  • before_update

  • before_validation

  • before_validation_on_create

  • before_validation_on_update

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

  • Section 3.11"




Rails Cookbook
Rails Cookbook (Cookbooks (OReilly))
ISBN: 0596527314
EAN: 2147483647
Year: 2007
Pages: 250
Authors: Rob Orsini

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net