Adding Hooks to Table Events

Problem

You want to run some code whenever a database row is added, updated, or deleted. For instance, you might want to send out email whenever a new blog post is created.

Solution

For Og, use the aspect-oriented features of Glue::Aspect. You can use its before and after methods to register code blocks that run before or after any Og method. The methods you e most likely to wrap are og_insert, og_update, and og_delete.

In the following code, I take the BlogPost class first defined in Recipe 13.12, and give its og_insert method an aspect that sends out email:

	require cookbook_dbconnect
	require og
	require glue/aspects

	class BlogPost
	 property :title, :content, String
	 after :on => :og_insert do |post|
	 puts %{Sending email notification of new post "#{post.title}"}
	 # Actually send the email here…
	 end
	end

	og_connect
	post = BlogPost.new
	post.title = Robots are taking over
	post.content = Think about it! When was the last time you saw another human?
	post.save!
	# Sending email notification of new post "Robots are taking over"

This technique works with ActiveRecord as well (since aspect-oriented programming is a generic technique), but ActiveRecord defines two different approaches: callbacks and the ActiveRecord::Observer class.

Any ActiveRecord::Base subclass can define a number of callback methods: before_find, after_save, and so on. These methods run before or after the corresponding ActiveRecord methods. Heres an callback-based ActiveRecord implementation of the Og example, running against the blog_post table first defined in Recipe 13.11. If you ran the previous example in a session, quit it now and start a new session.

	require cookbook_dbconnect
	activerecord_connect

	class BlogPost < ActiveRecord::Base
	 def after_create
	 puts %{Sending email notification of new blog post "#{title}"}
	 # Actually send the email here…
	 end
	end

	post = BlogPost.create(:title => Robots: Gentle Yet Misunderstood,
	 :content => Popular misconceptions about robERROR 40)
	# Sending email notification of new blog post "Robots: Gentle Yet Misunderstood

Discussion

ActiveRecords callback interface is simple, but its got a big disadvantage compared to Ogs. You can attach multiple aspects to a single method, but you can only define a callback method once.

This makes little difference when you only want the callback method to do one thing. But suppose that in addition to sending email whenever a blog post is created, you also want to notify people of new posts through an instant messenger client, and to regenerate static syndication feeds to reflect the new post.

If you used a callback, youd have to lump all of that code together in after_create. With aspects, each piece of functionality can go into a separate aspect. Its easy to add more, or to disable a single one without affecting the others. Aspects keep auxilliary code from cluttering up your core data classes.

Fortunately, ActiveRecord provides a strategy other than the callback methods. You can define a subclass of ActiveRecord::Observer, which implements any of the callback methods, and use the observe decorator to attach it to the classes you want to watch. Multiple Observers can watch a single class, so you can split up the work.

Heres a third example of the email notification code. Again, start a new session if you e following this recipe in irb.

	require cookbook_dbconnect
	activerecord_connect

	class BlogPost < ActiveRecord::Base
	end

	class MailObserver < ActiveRecord::Observer
	 observe BlogPost
	 def after_create(post)
	 puts %{Sending email notification of new blog post "#{post.title}"}
	 # Actually send the email here.
	 end
	end
	ActiveRecord::Base.observers = MailObserver

	post = BlogPost.new(:title => "ERROR 40",
	 :content => "ERROR ERROR ERROR ERROR ERROR")
	post.save
	# Sending email notification of new blog post "ERROR 40"

Note the call to ActiveRecord::Base.observers=. Calling this method starts the observer running. You can call ActiveRecord::Base.observers= whenever you need to add one or more Observers. Despite the implication of the method name, calling it twice won overwrite one set of observers with another.

In a Rails application, observers are traditionally started by putting code like the following in the environment.rb file:

	 # environment.rb
	 config.active_record.observers = MailObserver

When working with ActiveRecord, if you want to attach an Observer to a specific ActiveRecord class, you can name it after that class: for instance, BlogPostObserver will automatically observe the BlogPost class. Obviously, this only works for a single Observer.

See Also

  • Recipe 10.15
  • ActiveRecord callbacks documentation (http://rubyonrails.org/api/classes/ActiveRecord/Callbacks.html)
  • ActiveRecord Observer documentation (http://rails.rubyonrails.com/classes/ActiveRecord/Observer.html)
  • Og used to define a class called Og::Observer that worked like ActiveRecords ActiveRecord::Observer, but its been deprecated in favor of aspects; some of the documentation for Og::Observer is still online, so be careful not to get confused


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

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