really simple state machine

6 views
Skip to first unread message

wakathane

unread,
Oct 13, 2009, 6:15:39 PM10/13/09
to state-fu
Hi!

I seem too stupid to build a really simple state machine. All i want
is a state machine like this:

machine( :state ) do
state :step1 do
event :next, :to => :step2
end

state :step2 do
event :next, :to => :step3
end

state :step3 do
event :next, :to => :step4
end
end

But when I create a new instance of that model and call
"test.state.next!" it complain's:

ArgumentError: wrong number of arguments (0 for 1)
from (irb):4
from /usr/local/bin/irb:12:in `<main>'

When I rename :next in step1 to :next1, :next in step2 to :next2, etc.
it work's.But this is not how I want it... :(

Thanks for any help :)

Marshall

unread,
Oct 13, 2009, 6:40:33 PM10/13/09
to state-fu
That doesn't work because each event you declare is a new method
that's created on your object. In other words, you are trying to
define a "next" action on your object 3 times...

Here's what you're trying to do:

def MyModel
include StateFu

machine(:state) do
state :step1
state :step2
state :step3
state :step4

connect_states :step1, :step2, :step3, :step4
end
end

Now to proceed from one step to the next, you simply call next! on
your object...

>> my_model = MyModel.find(:first)
>> my_model.current_state.name
=> :step1
>> my_model.next!
>> my_model.current_state.name
=> :step2

David Lee

unread,
Oct 13, 2009, 7:16:17 PM10/13/09
to stat...@googlegroups.com
Marshall's absolutely correct.

To clarify a little further: the #next! method is already defined on StateFu#binding, so rather than calling a method to trigger your action, you were calling a method which triggers the only possible transition, otherwise raises an error if there is more than one possible transition.

If you prefer to have one event name, you can do this:

class K
  include StateFu

  machine( :state ) do
    state :step1 do
      event :go, :to => :step2
    end

    state :step2 do
      event :go, :to => :step3
    end

    state :step3 do
      event :go, :to => :step4
    end
  end
end

>> k = K.new
>> k.go! :step2
=> #<StateFu::Transition:0x18cfc70 event=:go origin=:step1 target=:step2 args=[] options={}>

However, it's the event (not the state) which determines the possible transitions:
>> k.state.machine.events.first
=> #<StateFu::Event::13043290 @name=:go targets=[:step2, :step3, :step4] origins=[:step1, :step2, :step3]>

So in doing this, you make it possible to change from any state to any other - probably not what you intended - thus, Marshall's suggestion makes perfect sense.

Hope this helps you understand what went wrong a little better.
cheers,
David



--
cheers,
David Lee

wakathane

unread,
Oct 15, 2009, 3:29:42 AM10/15/09
to state-fu
Hi!

Thanks for your help so far.

Unluckily I still got some problems. Imagine I have an online store
where customers can place offers. Each offer has to trough some steps
till it's fully processed. My current model looks like this:

http://pastie.org/655720

1. Problem
When creating a Order.new and saving it in the database, status is
NULL. Shouldn't it be set to "created" automatically as this is the
first state? Also no email get's sent, but this is connected to status
not being automatically set to "created" I guess.

2. Overall design
I'm really new to rails and especially state machines. Am I on the
right way or what could be done better?

Thanks :)

David Lee

unread,
Oct 15, 2009, 3:58:40 AM10/15/09
to stat...@googlegroups.com
1) What's your database column called? If your machine is called 'status', it should be 'status_field'. if you want to use something different you can do

machine :status, :field_name => 'my_field' do
  ....
end

Also, the on_entry event will not be triggered for the initial (by default first) state, as it doesn't "enter" that state - it's already in it. You might want to implement that as an after_create activerecord callback, or using an observer.

2) I can't see anything wrong with from the little I know about what you're trying to achieve.

cheers,
David
--
cheers,
David Lee
Reply all
Reply to author
Forward
0 new messages