Managing States using state_machine
Often times the state of an object is tracked through boolean attributes, but this solution doesn’t scale well since each new state requires a new column in the table along with logic to govern how the states change. If you have a model which you need to track the states of, the state_machine gem can be a great solution. It stores the state of the object in a string-type column (state
in the example below), and adding states and transitions is as easy as adding a couple lines of code to the model.
Here I’ve created a ruby model to describe my dogs.
So with this in place we can fire up irb and create a new instance of the Dog class:
As you can see, since we set initial: :sleeping
as an argument in the call to state_machine
all new instances are created with the state of "sleeping"
. One of the nice features of state_machine
is how easy it is to define events and how states should change as a result of calling an event. For example, gonzo
is sleeping now, so let’s see if we can go for a walk:
state_machine
provides nice helper methods named can_<event name>?
in order to check if calling the event has a transition defined for the current state. Since gonzo’s asleep, he can’t go for a walk, so if we try calling gonzo.walk
we get false. First things first, we have to wake him up before taking him on a walk:
When declairing a state, you can pass it a block to define other methods as I’ve done with the hungry
method. Since a dog is willing to have a cheese-snack any time of day, we can use the following to return true for that method call when in any states other than “sleeping”.
While this example is obviously a simple case, it’s easy to see how this approach scales well to more complicated state relationships. The state_machine
gem integrates with a number of libraries including ActiveModel classes, ActiveRecord models, DataMapper resources and Mongoid models. Another feature that some may like is its support for generating a directed graph using the graphviz library. If you ever need to track the state of a record, state_machine
is definitely worth a look. What’s your preferred method for tracking states?
Image is my own (it’s Gonzo).