A transition represents a state change for a specific attribute.

Transitions consist of:

  • An event
  • A starting state
  • An ending state
Methods
Attributes
[RW] args The arguments passed in to the event that triggered the transition (does not include the run_action boolean argument if specified)
[R] event The event that triggered the transition
[R] from The original state value before the transition
[R] from_name The original state name before the transition
[R] machine The state machine for which this transition is defined
[R] object The object being transitioned
[R] qualified_event The fully-qualified name of the event that triggered the transition
[R] qualified_from_name The original fully-qualified state name before transition
[R] qualified_to_name The new fully-qualified state name after the transition
[R] result The result of invoking the action associated with the machine
[R] to The new state value after the transition
[R] to_name The new state name after the transition
Public Class methods
perform(transitions, options = {}) {|| ...}

Runs one or more transitions in parallel. All transitions will run through the following steps:

  1. Before callbacks
  2. Persist state
  3. Invoke action
  4. After callbacks (if configured)
  5. Rollback (if action is unsuccessful)

Configuration options:

If a block is passed to this method, that block will be called instead of invoking each transition‘s action.

    # File lib/state_machine/transition.rb, line 28
28:       def perform(transitions, options = {})
29:         # Validate that the transitions are for separate machines / attributes
30:         attributes = transitions.map {|transition| transition.attribute}.uniq
31:         raise ArgumentError, 'Cannot perform multiple transitions in parallel for the same state machine attribute' if attributes.length != transitions.length
32:         
33:         success = false
34:         
35:         # Run before callbacks.  If any callback halts, then the entire chain
36:         # is halted for every transition.
37:         if transitions.all? {|transition| transition.before}
38:           # Persist the new state for each attribute
39:           transitions.each {|transition| transition.persist}
40:           
41:           # Run the actions associated with each machine
42:           begin
43:             results = {}
44:             success =
45:               if block_given?
46:                 # Block was given: use the result for each transition
47:                 result = yield
48:                 transitions.each {|transition| results[transition.action] = result}
49:                 !!result
50:               elsif options[:action] == false
51:                 # Skip the action
52:                 true
53:               else
54:                 # Run each transition's action (only once)
55:                 object = transitions.first.object
56:                 transitions.all? do |transition|
57:                   action = transition.action
58:                   action && !results.include?(action) ? results[action] = object.send(action) : true
59:                 end
60:               end
61:           rescue Exception
62:             # Action failed: rollback 
63:             transitions.each {|transition| transition.rollback}
64:             raise
65:           end
66:           
67:           # Run after callbacks even when the actions failed. The :after option
68:           # is ignored if the transitions were unsuccessful.
69:           transitions.each {|transition| transition.after(results[transition.action], success)} unless options[:after] == false && success
70:           
71:           # Rollback the transitions if the transaction was unsuccessful
72:           transitions.each {|transition| transition.rollback} unless success
73:         end
74:         
75:         success
76:       end
perform_within_transaction(transitions, options = {})

Runs one or more transitions within a transaction. See StateMachine::Transition.perform for more information.

    # File lib/state_machine/transition.rb, line 80
80:       def perform_within_transaction(transitions, options = {})
81:         success = false
82:         transitions.first.within_transaction do
83:           success = perform(transitions, options)
84:         end
85:         
86:         success
87:       end
Public Instance methods
action()

The action that will be run when this transition is performed

     # File lib/state_machine/transition.rb, line 157
157:     def action
158:       machine.action
159:     end
after(result = nil, success = true)

Runs the machine‘s after callbacks for this transition. Only callbacks that are configured to match the event, from state, and to state will be invoked.

The result can be used to indicate whether the associated machine action was executed successfully.

Once the callbacks are run, they cannot be run again until this transition is reset.

Halting

If any callback throws a :halt exception, it will be caught and the callback chain will be automatically stopped. However, this exception will not bubble up to the caller since after callbacks should never halt the execution of a perform.

Example

  class Vehicle
    state_machine do
      after_transition :on => :ignite, :do => lambda {|vehicle| ...}

      event :ignite do
        transition :parked => :idling
      end
    end
  end

  vehicle = Vehicle.new
  transition = StateMachine::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
  transition.after(true)
     # File lib/state_machine/transition.rb, line 309
309:     def after(result = nil, success = true)
310:       @result = result
311:       
312:       catch(:halt) do
313:         unless @after_run
314:           callback(:after, :success => success)
315:           @after_run = true
316:         end
317:       end
318:       
319:       true
320:     end
attribute()

The attribute which this transition‘s machine is defined for

     # File lib/state_machine/transition.rb, line 152
152:     def attribute
153:       machine.attribute
154:     end
attributes()

A hash of all the core attributes defined for this transition with their names as keys and values of the attributes as values.

Example

  machine = StateMachine.new(Vehicle)
  transition = StateMachine::Transition.new(Vehicle.new, machine, :ignite, :parked, :idling)
  transition.attributes   # => {:object => #<Vehicle:0xb7d60ea4>, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}
     # File lib/state_machine/transition.rb, line 181
181:     def attributes
182:       @attributes ||= {:object => object, :attribute => attribute, :event => event, :from => from, :to => to}
183:     end
before()

Runs the machine‘s before callbacks for this transition. Only callbacks that are configured to match the event, from state, and to state will be invoked.

Once the callbacks are run, they cannot be run again until this transition is reset.

Example

  class Vehicle
    state_machine do
      before_transition :on => :ignite, :do => lambda {|vehicle| ...}
    end
  end

  vehicle = Vehicle.new
  transition = StateMachine::Transition.new(vehicle, machine, :ignite, :parked, :idling)
  transition.before
     # File lib/state_machine/transition.rb, line 236
236:     def before
237:       result = false
238:       
239:       catch(:halt) do
240:         unless @before_run
241:           callback(:before)
242:           @before_run = true
243:         end
244:         
245:         result = true
246:       end
247:       
248:       result
249:     end
inspect()

Generates a nicely formatted description of this transitions‘s contents.

For example,

  transition = StateMachine::Transition.new(object, machine, :ignite, :parked, :idling)
  transition   # => #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
     # File lib/state_machine/transition.rb, line 363
363:     def inspect
364:       "#<#{self.class} #{%w(attribute event from from_name to to_name).map {|attr| "#{attr}=#{send(attr).inspect}"} * ' '}>"
365:     end
loopback?()

Does this transition represent a loopback (i.e. the from and to state are the same)

Example

  machine = StateMachine.new(Vehicle)
  StateMachine::Transition.new(Vehicle.new, machine, :park, :parked, :parked).loopback?   # => true
  StateMachine::Transition.new(Vehicle.new, machine, :park, :idling, :parked).loopback?   # => false
     # File lib/state_machine/transition.rb, line 169
169:     def loopback?
170:       from_name == to_name
171:     end
perform(*args)

Runs the actual transition and any before/after callbacks associated with the transition. The action associated with the transition/machine can be skipped by passing in false.

Examples

  class Vehicle
    state_machine :action => :save do
      ...
    end
  end

  vehicle = Vehicle.new
  transition = StateMachine::Transition.new(vehicle, machine, :ignite, :parked, :idling)
  transition.perform          # => Runs the +save+ action after setting the state attribute
  transition.perform(false)   # => Only sets the state attribute
     # File lib/state_machine/transition.rb, line 201
201:     def perform(*args)
202:       run_action = [true, false].include?(args.last) ? args.pop : true
203:       self.args = args
204:       
205:       # Run the transition
206:       self.class.perform_within_transaction([self], :action => run_action)
207:     end
persist()

Transitions the current value of the state to that specified by the transition. Once the state is persisted, it cannot be persisted again until this transition is reset.

Example

  class Vehicle
    state_machine do
      event :ignite do
        transition :parked => :idling
      end
    end
  end

  vehicle = Vehicle.new
  transition = StateMachine::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
  transition.persist

  vehicle.state   # => 'idling'
     # File lib/state_machine/transition.rb, line 270
270:     def persist
271:       unless @persisted
272:         machine.write(object, :state, to)
273:         @persisted = true
274:       end
275:     end
reset()

Resets any tracking of which callbacks have already been run and whether the state has already been persisted

     # File lib/state_machine/transition.rb, line 353
353:     def reset
354:       @before_run = @persisted = @after_run = false
355:     end
rollback()

Rolls back changes made to the object‘s state via this transition. This will revert the state back to the from value.

Example

  class Vehicle
    state_machine :initial => :parked do
      event :ignite do
        transition :parked => :idling
      end
    end
  end

  vehicle = Vehicle.new     # => #<Vehicle:0xb7b7f568 @state="parked">
  transition = StateMachine::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)

  # Persist the new state
  vehicle.state             # => "parked"
  transition.persist
  vehicle.state             # => "idling"

  # Roll back to the original state
  transition.rollback
  vehicle.state             # => "parked"
     # File lib/state_machine/transition.rb, line 346
346:     def rollback
347:       reset
348:       machine.write(object, :state, from)
349:     end
within_transaction() {|| ...}

Runs a block within a transaction for the object being transitioned. By default, transactions are a no-op unless otherwise defined by the machine‘s integration.

     # File lib/state_machine/transition.rb, line 212
212:     def within_transaction
213:       machine.within_transaction(object) do
214:         yield
215:       end
216:     end
Protected Instance methods
callback(type, context = {})

Runs the callbacks of the given type for this transition. This will only invoke callbacks that exactly match the event, from state, and to state that describe this transition.

Additional callback parameters can be specified. By default, this transition is also passed into callbacks.

     # File lib/state_machine/transition.rb, line 386
386:       def callback(type, context = {})
387:         context = self.context.merge(context)
388:         
389:         machine.callbacks[type].each do |callback|
390:           callback.call(object, context, self)
391:         end
392:       end
context()

Gets a hash of the context defining this unique transition (including event, from state, and to state).

Example

  machine = StateMachine.new(Vehicle)
  transition = StateMachine::Transition.new(Vehicle.new, machine, :ignite, :parked, :idling)
  transition.context    # => {:on => :ignite, :from => :parked, :to => :idling}
     # File lib/state_machine/transition.rb, line 376
376:       def context
377:         @context ||= {:on => event, :from => from_name, :to => to_name}
378:       end