Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

wilhelm http://webjazz.blogspot.com

« Newer Snippets
Older Snippets »
Showing 1-1 of 1 total  RSS 

State change observer for ActiveRecord in Rails

This is something to observe state changes as indicated by an attribute in an ActiveRecord Object in Rails. Normally, if you just need to observe an object and do things based on what state it's in, use the Observer provided in Rails. You can then use callbacks to do whatever you need to in the observer. However, if you want to do something upon a particular state transition, then you can try the stuff below:

Create a model like this. Here, the attribute mode keeps track of the state.
   1  
   2  class CreateCarTransmission < ActiveRecord::Migration
   3    def self.up
   4      create_table :car_transmission do |t|
   5        t.column :engine_id, :integer, :null => false
   6        t.column :mode, :string, :null => false, :default => "park"
   7      end
   8    end
   9  
  10    def self.down
  11      drop_table :car_transmission
  12    end
  13  end

In the model, you include the state transition observable class, and call state_observable.
   1  
   2  class CarTransmission < ActiveRecord::Base
   3    include StateTransition::Observable
   4    state_observable CarTransmissionNotifier, :state_name => :mode
   5  end

Then you define a notifier class that has different callbacks based on the transitions. It follows the pattern, "#{state_name}_from_#{state you're coming from}_to_#{state you're going to}"
   1  
   2  class CarTransmissionNotifier < StateTransition::Observer
   3    def mode_from_drive_to_reverse(transmission)
   4      # send out mail and flash lights about how this is bad.
   5    end
   6  end


So whenever you change the state from "drive" to "reverse" of a car transmission model in the controller, the notifier will fire up.

To use it, put the following code in a file called 'state_transition.rb', put it in your lib/ directory in rails.
   1  
   2  require 'observer'
   3  
   4  module StateTransition
   5    module Observable
   6      class StateNameNotFoundError < RuntimeError
   7        def message
   8          "option :state_name needs to be set to the name of an attribute"
   9        end
  10      end
  11  
  12      def self.included(mod)
  13        mod.extend(ClassMethods)
  14      end
  15  
  16      module ClassMethods
  17  
  18        def state_observable(observer_class, options)
  19          raise StateNameNotFoundError.new if options[:state_name].nil?
  20          state_name = options[:state_name].to_s
  21          
  22          include Object::Observable
  23  
  24          define_method(:after_initialize) do 
  25            add_observer(observer_class.new)
  26          end
  27  
  28          define_method("#{state_name}=") do |new_state|
  29            old_state = read_attribute(state_name)
  30            if old_state != new_state
  31              write_attribute(state_name, new_state) # TODO yield the update method
  32              changed
  33              notify_observers(self, state_name, old_state, new_state)
  34            end
  35          end
  36        end
  37  
  38      end
  39      
  40    end
  41  
  42    class Observer
  43      def update(observable, state_name, old_state, new_state)
  44        send("#{state_name}_from_#{old_state}_to_#{new_state}", observable)
  45      rescue NoMethodError => e
  46        # ignore any methods not found here
  47      end  
  48    end
  49  
  50  end


more details here
« Newer Snippets
Older Snippets »
Showing 1-1 of 1 total  RSS