Ruby On Rails, Design, Simplicity, Web 2.0, Ajax, Mac and Tons of Pizza.

Mar 17

Observers: observing when changes have been made...

Posted by Annalisa Afeltra in Ruby on Rails - 3 comments digg this add to delicious

I wanted to find a solution that only sends an email to notify when a change has been made to the page. I came across the Observer. It works great when you need to compare if the value have been changed from before the save button to after.

This is how it works:

In the controller, add the following at the top of the page:


observer :mail_observer

and in the model, add the following to get the changed attributes:


attr_accessor :changed_attributes

Create a new model:

mail_observer.rb

Your mail_observer should look similar to this, I call two callback methods before_save and after_save:


class MailObserver < ActiveRecord::Observer
  #observe and the name of your model
  observe Task 

  def before_save(model)

   #Place the old values into a hash table only if it is not a new record being inserted
    old_attr = Hash.new
    if !model.new_record?
      old_model = model.class.find(model.id)
      old_attr = old_model.attributes
    end

    tmp_diff = Hash.new

    #delete the values in the hash table where the values have not changed, leaving you with the changed values
    model.attributes.delete_if do |key,value|
      old_attr[key] == value    
    end.keys.each do |k|
      tmp_diff[k] = old_attr[k]
    end

    model.changed_attributes = tmp_diff   
  end

In the after_save function I check which values have changed by !model.changed_attributes[‘resource_name’].nil?, for example if a task that has been assigned to a person, is changed to another person, an email is sent to alert the new person that a task has been assigned to them.


  #the after save function you can check which values have been changed and do something for it, depending on what has changed

  def after_save(model)      
      #task resource_name
      if !model.changed_attributes['resource_name'].nil?
         #send an email to the person that has been assigned this new task
         puts 'the owner of this task is has been changed.' 
      end
 end

This could be a good example to check when changes have been made to a page and to alert the changes that have been made.

Comments

  • Craig Webster

    Posted on March 19

    One important thing to remember about observers is that the processing they do will be done as part of the HTTP request-response cycle. This means that if you have long-running code in the observer the response to the user will be slow. Even if you use some sort of Ajax call to remove the user from the slow response you're still tying up one of your dispatchers for a long time stopping it from serving other people. To keep response times and user throughput high it's advisable to push any heavy lifting from the observer into a background task. For sending email this could be done using ARMailer (http://seattlerb.rubyforge.org/ar_mailer/), for other tasks you may want to look into setting up BackgrounDRb or BackgroundJob (http://agilewebdevelopment.com/plugins/bj) and letting that execute the task outside of the Rails stack where it won't slow up your web app.
  • ryan

    Posted on March 27

    Good post. One syntactical thing you should keep in mind, is to avoid using "if !something" - instead use "unless". So...
    if !model.attrs.nil?
    
    becomes...
    unless model.attrs.nil?
    
    It's more readable, and a good idiom to adopt.
  • Annalisa

    Posted on March 31

    Hi Ryan, thanks for your comment and your coding advice, it is much better to understand. I will definitely make use of this in the future.

Post a comment

Categories:

Tags:

Powered by Mephisto, Valid XHTML 1.1, Valid CSS - Supported by Wave Factory