Friday, February 20, 2009

What's next with acts_as_state_machine?

I've been using acts_as_state_machine and there seems to be at least two convenience methods missing that I find quite useful:
  1. next_state - what state will we be transitioning to
  2. next_states - list of states that we still need to transition to
Drop the following in a suitable place (your model using acts_as_state_machine will do) and abuse it to your hearts content:
# Monkey patch acts_as_state_machine to allow us to see what the next states are
# for the current state
module ScottBarron
module Acts
module StateMachine
module InstanceMethods
def next_state(state=nil)
state ||= current_state()
self.class.read_inheritable_attribute(:transition_table).each_value do |event|
event.each do |transition|
return transition.to if transition.from == state
end
end
nil
end

def next_states(state=nil)
state ||= current_state()
states = []
while state = next_state(state)
states << state
end
states
end
end
end
end
end
Thanks to Lourens Naude's' post on acts_as_state_machine for providing me with some ideas and to Scott Barron for the great acts_as_state_machine plugin.


7 comments:

sh.p said...

Hi, your code is exactly what I was looking for! However next_states seems to make infinite loop to me. I'm trying to fix it however I'm not used to Ruby language though :)

Charl said...

@sh.p: Can you archive your rails project and mail it to me to have a look at for you? You can mail it to charl [at] ntrippy.net.

sh.p said...

Hi Charl..
Thank you for the response. I just tried once again it with your code and it worked! I'm sorry to confuse you.
By the way, I've been spending about an hour to make "available_events(state=nil)" method. I'd like to have a method that returns a list of available events like the example below.

state :inactive
state :active
state :expired

event :expire do :from => :active, :to => :expired end

> @event.available_events(:active)
- :expire

Any good ideas? I'm struggling with the syntax ha ha.

Anyway thank you very much for giving me the greatest inspiration.

Charl said...

@sh.p: @event.states will return an array of the defined states that were declared in your model.

sh.p said...

I know the method returns an array of defined states. But what I meant is events can be fired based on current state. I think knowing what events can be fired is more useful than what states can be moved.

Charl said...

@sh.p: IDo you want a list of all states that follow the state you supply to available_events? If so, why not use next_states in the post to suit your needs?

sh.p said...

Hi Charl

I want to get a list of events that can change the state to next_states. Like below

>@event.current_state
- :active
> @event.next_states
- [:expired]
> @event.available_events
- [:expire] # This is what I want to have.

I want to know "how" to change the state to "next_states" from "current_state". I can get next available states but don't know which events do it.
I'm not sure did I make myself clear or my approach is right one.

About Me

My photo
I love solving real-world problems with code and systems (web apps, distributed systems and all the bits and pieces in-between).