Practical eCommerce

 

Acts_As_State_Machine Is Now A Gem

The Rails state machine plugin has been converted to a gem.

Author: Brian Getting
Publish Date: October 07, 2008
Blog: Developers' Corner
Tags: ruby, rails, acts_as_state_machine, gem, plugin

avatar

Things in the Rails world seem to be moving pretty quickly lately, particularly as Github becomes more and more popular. One of the things that has been happening is that plugins and gems are being updated faster and faster, and in many cases plugins that are not application-specific are becoming gems. Once such example is the acts_as_state_machine plugin, which has recently been turned into the AASM gem.

First off, the reason that some plugins are becoming gems, as I mentioned before, is two-fold. The first is that Rails now includes gem dependencies, as I wrote about last time. But what plugins are good candidates for a gem? As I mentioned, if a plugin is not application-specific, it is a good candidate for a gem since it can be used equally between apps. What does that mean? An example is probably best.

Let's take the only Rails plugin that I have written to date, called acts_as_mailchimp, which is used to interact with the Mailchimp email marketing service. One thing that is required for that plugin is that you have a Mailchimp account. The plugin handles interaction with the Mailchimp API in order to update mailing lists and such. As you can imagine, each application would have it's own account at Mailchimp, and the mailing lists would be customized for each application. This is not the most ideal candidate for a gem, since each application needs to be configured differently. In other words, the plugin handles interactions that are specific to each application.

In contrast, the acts_as_state_machine plugin provided a state machine, which is an engine for remembering the state of a class, and transitions between those states. In this case the plugin is a perfect gem candidate because it is something that can easily be used among many applications. In fact, that is what they did in creating the AASM gem. Let's take a look at how to use this new version of the state machine.

Installation

To install the gem, you have two choices. You can simply install the gem manually on your machine using the following commands:

sudo gem sources -a http://gems.github.com
sudo gem install rubyist-aasm

The first command will update your gem sources with the Github gem repository, which only needs to be done once. The second command installs the rubyist-aasm gem to you machine. Notice that with Github gems, the name of the gem will be username-gem name, which is the convention that they are starting. Because of this, installing the gem using gem dependencies is done with the following line in you environment.rb file:

config.gem 'rubyist-aasm', :version => '~> 2.0.2', :lib => 'aasm', :source => "http://gems.github.com"

As you can see, when using dependencies we need to tell it that the lib variable is aasm, which allows Rails to understand that we are requiring the AASM gem. It's a small thing to remember, but important if you are installing gems via dependencies. Once you have set your dependencies, you can install all gems for your application at once using the command:

rake gems:install

Doing so will install all the gems that your application is dependent on. But enough about that, let's take a quick look at the differences in the AASM gem, and how to use it. I outlined usage of the original actsas_statemachine plugin before, and wanted to be sure to cover the changes.

Usage

First off is that states are no longer limited to Activerecord objects. In fact, the new AASM gem allows you to add states to any class that you want. Really all you need is a field somewhere that will be storing the state of your object, and you can run from there. Let's look at an example model file to help explain how to use it:

class Invoice < ActiveRecord::Base
  include AASM

  aasm_column :state
  aasm_initial_state :pending
  aasm_state :pending
  aasm_state :viewed, :enter => :view_invoice
  aasm_state :printed, :enter => :print_invoice

  aasm_event :view do
    transitions :to => :viewed, :from => [:pending]
  end

  aasm_event :print do
    transitions :to => :printed, :from => [:viewed, :pending]
  end

  def view_invoice
    # Called when record moves into the "viewed" state.
  end

  def print_invoice
    # Called when record moves into the "printed" state.
  end

end

Let's take a minute to see what we have done. First of all, we have to include the AASM methods in our model, which is done with the include AASM line above.

Secondly we define the column that will be holding our state, which in our case is a field called state. In our case, this field will be holding a text string that is either pending, viewed or printed, based on the states that we defined in our class file. One thing to notice is that when we define the states, we can define a method to fire when a record enters that state.

In our example, we are telling the Invoice class that when an instance of this class moves into the viewed state, we want it to run the method called view_invoice. Similarly, we have also said that when the instance of this class moves to the printed state, we want it to run the print_invoice method. I have not defined either of these methods, but rather stubbed them out in the code to illustrate how it is done. In my experience, this can replace observers in many instances where you want something to happen based on a state change, and not necessarily every time a record is created or updated.

Finally, we define the transitions that this class is allowed to go through. As you can see, our record starts out in the pending state. We have defined 2 events, which are called view and print. Looking closely at those event definitions, you will see that a record can only move to the viewed state from the pending state. However, a record can move to the printed state regardless of it's previous state. This is a great feature of AASM in that you can control whether or not a record is allowed to make a transition based on the state that it is currently in.

Once we have defined our events, we are automatically given some new methods for each instance of this class. For example, in our controller code we can use something like the following in order to initiate a transition:

@invoice = Invoice.find(params[:id])
@invoice.view!

As you can see, we first find the invoice that we want to work with, and then we can use the view! method to transition that instance to the viewed state. Based on the events that we have created in our class file, we are now allowed to use the following methods:

instance.view!
instance.print!

Simply putting an exclamation mark after our defined event title makes it all happen. This is about as simple as it can be.

With any luck this helps people to continue taking advantage of the functionality offered by the AASM gem, and also to help them make the transition from the plugin to the gem. One last thing to mention is that if you are using the RESTful_authentication there is now a flag in the generator that will allow you to use the AASM gem rather than the older acts_as_state_machine plugin.

Add a Bookmark: Add 'Acts_As_State_Machine Is Now A Gem' to Del.icio.us Digg 'Acts_As_State_Machine Is Now A Gem' on Digg.com Submit 'Acts_As_State_Machine Is Now A Gem' to reddit.com Blink 'Acts_As_State_Machine Is Now A Gem' Add 'Acts_As_State_Machine Is Now A Gem' to dzone Seed 'Acts_As_State_Machine Is Now A Gem' on Newsvine Add 'Acts_As_State_Machine Is Now A Gem' to Furl Add 'Acts_As_State_Machine Is Now A Gem' to Spurl Add 'Acts_As_State_Machine Is Now A Gem' on simpy.com Add 'Acts_As_State_Machine Is Now A Gem' to fark.com BlogMark 'Acts_As_State_Machine Is Now A Gem' Add 'Acts_As_State_Machine Is Now A Gem' to Yahoo! myweb2 Add 'Acts_As_State_Machine Is Now A Gem' to wists.com Stumble It!

0 Comments

Sign-up to receive EcommerceNotes, our acclaimed email newsletter.

View A Sample | Privacy

Bloggers Wanted

We’re looking for merchants and other ecommerce professionals to share their experiences with our readers. If this interests you, we invite you to contact us.

Inside Practical eCommerce