Acts_as_state_machine

When mapping the flow of an application, we usually have various states for a single object. These states are then joined with lines showing how an object can transition from one state to another. Each state will be unique; it may be just simply have a status flag, or it could open up new functionality within the app. For example, an e-commerce application may have a system for package tracking. When customer pays for a product, that product will have a status of 'paid'. Based on the paid status, the seller will be notified that the product needs to be shipped and the customer will gain the ability to write a review.

Traditionally, we would have to create methods that dealt with switching and checking states. Thankfully that has all changed with the wonderful ActsAsStateMachine plugin. What I like best about ActsAsStateMachine is that it has its own methods in handling states and event transitions that won't get lost with other methods within the model. I will go more into detail soon, but first we need to create a quick application to showcase the awesomeness of ActsAsStateMachine!

Let's create a baseball application that will display scores of current games. Each game will be in the database before it starts, allowing users to view if tickets are available. When the game is live, ticket information will not be needed and a scoreboard with all the innings will be displayed instead. When the game is over, only the final score will appear with information for the next game.

To get started, first install the plugin:

ruby script/plugin install http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk/

Then within our Game model, add the following:

acts_as_state_machine, :column => :game_state, :initial => :pending

Here we are simply telling the Game model to act as a finite state machine. We are setting the column that will hold the Game's state as game_state. By default, ActsAsStateMachine will use the state column. This can cause problems since a state column in most applications will hold location information. So by specifying a column name, we can avoid column problems. The last portion will set the initial state of a newly created Game object to pending. It is similar to creating a migration and setting the column to a default value, but if that default value ever needs to change, a new migration would have to be created. By setting a initial value, we can easily change just that one line. Now lets define all the various states for a game. Based on the app's requirements, a game will have three states: Pending, Live and Final. Defining states is as easy as adding:

state :pending
state :live
state :final

Our Game model now has states and with each state definition new methods are created. These methods may come in handy for state-specific validations or can be used in conditionals within the views that will load certain partials. For example, instead of doing @game.state == "live", we can use @game.live?. With all the states for Game defined, it is time to add events that will transition the game from one state to another. ActsAsStateMachine has it's own methods for creating events, which is basically a loop. We start by defining the event loop, giving the event a name and then specifying transitions within.

event :start_game do
  transitions :from => :pending, :to => :live
end

event :end_game do
  transitions :from => :live, :to => :final
end

With these events we can now transition a game object's state by using @game.start_game! and @game.end_game!. Keep in mind each event can hold many transitions, we can combine the two event methods into one as long as the :from portion is different. It wouldn't make much sense in the context of our example, however, because it is linear.

We have had the app up for a few weeks now and baseball fans are really digging the slick up-to-the-minute scores that we update through AJAX calls. Eventually we will run into our first rain delay, which will lead to problems. Fans will start thinking the app has stopped updating and our servers will keep running expensive AJAX updates over a game that has turned idle. It is time to introduce the rain delay state and event, making our simple app less linear.

state :rain_delay
  
event :rainout do
  transitions :from => :live, :to => :rain_delay
end

With a rain delay, a choice will be made by the umpires. If enough innings have been played, the game can end with the current score being final. Otherwise the game can be canceled and be rescheduled at a later date. Let's add the new canceled state and transitions events from rain_delay. Lets also add a new transition into the end_game event for rain_delay games that have played enough innings to be called final.

state :canceled
  
event :end_game do
  transitions :from => :live, :to => :final
  transitions :from => :rain_delay, :to => :final
end

event :cancel_game do
  transitions :from => :rain_delay, :to => :canceled
end

Let's say if a game is canceled it is still in our database for historical purposes and a new game will be created with some data from the canceled game. Let's also say that the reschedule_game method will create a new game from a canceled game. ActsAsStateMachine lets us attach callbacks like state events. Basically we want to run the reschedule_game method whenever a game's state changes to canceled. To accomplish this, we simply add :enter => methodname after defining the state as so:

state :canceled, :enter => :reschedule_game

Now whenever a game's state switches to canceled, a copy will automatically be made through the reschedule_game method. Besides enter, ActsAsStateMachine also has after and exit options. After would run after the state switch has been made and exit will be executed when the object is transitioning away from the state.

ActsAsStateMachine comes in handy when a object's status goes through many changes. I hope I have shown you how easy it is to define states, create transitions and implement ActsAsStateMachine into a model. Here is what our final code looks like:

acts_as_state_machine, :column => :game_state, :initial => :pending

# States
state :pending
state :live
state :final
state :rain_delay
state :canceled, :enter => :reschedule_game

# Transition Events
event :start_game do
  transitions :from => :pending, :to => :live
end

event :end_game do
  transitions :from => :live, :to => :final
  transitions :from => :rain_delay, :to => :final
end

event :rainout do
  transitions :from => :live, :to => :rain_delay
end

event :cancel_game do
  transitions :from => :rain_delay, :to => :canceled
end



Backup

Living with Regret

Many of my articles deal with researching and the effect it has on the company's dealings with clients. Now, I feel that another issue has to take the forefront: system and assets back-up. I have had the worst luck lately when dealing with computers, company data and the need to back things up. Working at a Web firm, it's easy to take backing up for granted because everything already has two copies: all the articles, client assets, help archives, etc. exist both on our local drives as well as on the Web servers. But this is the exception to the rule as most businesses don't have such redundancy in place.

I still can recall my personal data loss tragedies... One day I accidentally erased my first PC's 500MB drive trying to retrieve a paper I wrote for history class. Another day I lost all my documents, media and impressive collection of ms-dos based games to a suddenly defective drive. The memories haunt me...

Thanks to continually dropping technology prices, a back-up array or separate storage solution has fallen within reach of the average home user. Still, people are losing their data in their own personal tragedies every day, simply because data back-ups only gets serious consideration about five seconds too late.

A while ago, I consulted with a company on a new computer setup. Under normal circumstances, this should have been a simple, straight-forward, "Buy, Back-up, Program and Go." Unfortunately, their current computer was using Windows '98 and its drive had crashed an hour before I had gotten there. Once a Windows '98 drive has spun its last sector there's simply no hope. I had the unpleasant honor of explaining that their data and projects had gone to 'a better place', all because they hadn't taken my suggestion to pick up a 80GB back-up drive for an easy $70.

The data of any business is a precious commodity, and working without a back-up system is walking on a tightrope without a net. Thankfully, there are many data storage solutions that can meet the needs and budgets of business and personal users.

Hardware Solutions

One simple solution that a user can get either for business or personal use is a 1TB (terabyte) drive, an amount that is virtually impossible to fill without a vast media collection. While this drive is not lacking in capacity, I would be concerned that a drive failure would result in such an immense loss. Personally, I prefer to spread out all my data on multiple drives so that if one fails I have a copy of it somewhere else.

For a business or user that needs to back-up multiple computers, a networked or wireless drive may be an excellent solution. The D-Link DSM-G600 Wireless G Network Storage Enclosure allows you to place drives on a shared network. Another solution would be an attached network storage like the Iomega StorCenter 1TB WI-FI Network storage drive. The drives are already formatted and ready to go, and have wireless connectivity and network adapters for additional server storage.

For those users that need storage on a tight budget I would recommend one of two choices. A 500GB external drive like the Seagate Freeagent Desktop costs between $90-150. For the more ambitions, you can combine a 500GB hard drive (about $100 and getting cheaper) with an external enclosure (check out the Eagle Consus W-Series SATA to USB and the eSATA External Storage System (ET-CSWESU2-BK) Black).

I recently have been introduced to an innovative storage solution called Drobo, the world's first storage robot. I have to say the concept looks promising, I wish that I could get my hands on one to play with. Based on information from their site, here are some pros and cons of the Drobo:

Pros:

  • You can swap drives (SATA only please) in and out of Drobo and data is automatically and redundantly redistributed to protect from drive failure. This is like RAID only better: I don't trust RAID based systems because of their rigid nature. With RAID, adding or removing a drive requires a full reboot and, depending on the RAID configuration, a single drive failure could still corrupt the whole array.
  • No babysitting required, the Drobo takes care of itself.
  • There's no loss of productivity between files and data while drive swapping.

Cons:

  • The Drobo's price of $499 and up is a significant roadblock to becoming an early adopter. Keep an eye out for this price to start dropping, however, as the technology spreads.
  • It only comes with USB 2.0 connections, eSATA and standard networking capabilities would have been welcome features.

While using an external drive is sufficient for many purposes, some users are turning to software solutions that help automate the back-up process.

Software Solutions for Macs

There is an integrated solution that ships with every new Mac called Time Machine. Time Machine makes a full copy of your computer's data when it is initialized and then simply records the changes made to your data. Its automation is paired with a fun, intuitive user interface that let's a user 'fly through time' to find the file that was deleted, edited or saved over. Thanks to its excellent integration within OSX and other peripherals like Time Capsule, Time Machine is the likely choice for backing up Macs.

One other possible solution is MacBackups which does online, offsite back-ups of your Mac.

Software Solutions for PCs

Nero offers a back-up feature in its Nero 8 software. It can automate the back-up process and allows for manual back-ups as well

Norton Ghost is also an excellent option. It's not a tradition back-up program in that you have to restart and load PC-dos in order to make your back-up. The benefit to this approach is that it can restore your entire computer with your programs intact rather than simply your documents.

I hope this is a resource that can help make your back-ups easy and painless, but no matter what, please, PLEASE, back up your files!




RSS Feed


CATEGORIES


ARCHIVES


BOOKMARKED


Add to Technorati Favorites