I recently re-wrote an old model that desperately needed a formalized state machine definition (instead of the fragile logic I originally strung together). After reviewing both AASM (formerly acts_as_state_machine) and Workflow, I went with the former for a couple of reasons.
- AASM seemed to be a bit more mature
- It made more sense to describe an event (i.e. state machine input) once, with all the transitions it could cause and its to/from states, rather than defining it a separate time for each state-transition pair it could affect.
For example, one might define a traffic light in AASM as follows:
aasm_state :red, :yellow, :green
aasm_event :timer_done do
transitions :from => :red, :to => :green
transitions :from => :green, :to => :yellow
transitions :from => :yellow, :to => :red
end
Whereas Workflow would have one define it:
workflow do
state :red do
event :timer_done, :transitions_to => :green
end
state :green do
event :timer_done, :transitions_to => :yellow
end
state :yellow do
event :timer_done, :transitions_to => :red
end
end
I suppose it depends on the situation whether it’s clearer to define states - and everything that can cause one to leave that state - or to define events - and all the states on which they operate.
But beware: AASM is not a perfect finite state machine. You cannot auto-transition out of the initial state via the :after_enter method. The initializer code will set your model’s state variable to whatever is defined by aasm_initial_state after all callbacks are run, even if the state machine transitions to a new state due to those initial states’ callbacks.
For example, the following code would result in a :red initial state, not a :green initial state as would be expected:
aasm_initial_state :red
aasm_state :red, :after_enter => Proc.new { |x| x.go_green! }
aasm_event :go_green do
transitions :from => :red, :to => :green
end





