state-machines / state_machines

Adds support for creating state machines for attributes on any Ruby class
https://github.com/state-machines/state_machines
MIT License
814 stars 91 forks source link

Calling state_paths() results in infinite loop #58

Closed SirRawlins closed 7 years ago

SirRawlins commented 7 years ago

Afternoon Folks,

I have a machine defined which allows fairly broad transitions to/from various states as follows:

state_machine :state, initial: :draft do
    # When the incident is being investigated by the team.
    transition all => :under_investigation, :on => :under_investigation
    # Transition back to an open state.
    transition all => :open, :on => :open
    # When the issue is resolved, but taking time to recover.
    transition all => :in_recovery, :on => :in_recovery
    # Transition to a closed state.
    # Don't allow posting direct to closed, must be open first.
    transition all - [:draft] => :closed, :on => :close
end

However, when calling state_paths() on this object it just appears to hang or get caught in some form of an infinite loop. If I remove either :in_recovery or :under_investigation state/transition the problem appears to go away.

Any suggestions on what might be causing this? Am I doing something fundamentally wrong? Or is this a bug in the gem somewhere?

This seems to be the case running various 0.4.x and 0.5.x builds of state_machines. (May also be an issue further back)

Appreciate any insight.

Rob

SirRawlins commented 7 years ago

A little experimentation has found that any and all appear to be self-referential, so allowing transition from any creates a path back to itself.

# When the issue is resolved, but taking time to recover.
transition all => :in_recovery, :on => :in_recovery

Allows me to fire in_recovery! on an object which is already in_recovery, to put it in_recovery again. If I negate the self-reference for all the transitions like so:

# When the issue is resolved, but taking time to recover.
transition all - :in_recovery => :in_recovery, :on => :in_recovery

Then the infinite loop when calling state_paths() no longer appears to occur. So technically I can get things working, but it feels a little verbose and counter-intuitive.

Any suggestions on a better approach?

SirRawlins commented 7 years ago

Closing this off as have learned it was my own mistake. I wasn't aware that state_paths is a recursive lookup of all potential routes, and my structure allowed for self-references which go on forever.

What I was actually after was state_events which gives you just the collection 1 level deep.