class StateMachine::TransitionCollection

Represents a collection of transitions in a state machine

Attributes

skip_actions[R]

Whether to skip running the action for each transition's machine

skip_after[R]

Whether to skip running the after callbacks

use_transaction[R]

Whether transitions should wrapped around a transaction block

Public Class Methods

new(transitions = [], options = {}) click to toggle source

Creates a new collection of transitions that can be run in parallel. Each transition must be for a different attribute.

Configuration options:

  • :actions - Whether to run the action configured for each transition

  • :after - Whether to run after callbacks

  • :transaction - Whether to wrap transitions within a transaction

Calls superclass method
   # File lib/state_machine/transition_collection.rb
22 def initialize(transitions = [], options = {})
23   super(transitions)
24   
25   # Determine the validity of the transitions as a whole
26   @valid = all?
27   reject! {|transition| !transition}
28   
29   attributes = map {|transition| transition.attribute}.uniq
30   raise ArgumentError, 'Cannot perform multiple transitions in parallel for the same state machine attribute' if attributes.length != length
31   
32   assert_valid_keys(options, :actions, :after, :transaction)
33   options = {:actions => true, :after => true, :transaction => true}.merge(options)
34   @skip_actions = !options[:actions]
35   @skip_after = !options[:after]
36   @use_transaction = options[:transaction]
37 end

Public Instance Methods

perform(&block) click to toggle source

Runs each of the collection's 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)

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_collection.rb
50 def perform(&block)
51   reset
52   
53   if valid?
54     if use_event_attributes? && !block_given?
55       each do |transition|
56         transition.transient = true
57         transition.machine.write(object, :event_transition, transition)
58       end
59       
60       run_actions
61     else
62       within_transaction do
63         catch(:halt) { run_callbacks(&block) }
64         rollback unless success?
65       end
66     end
67   end
68   
69   if actions.length == 1 && results.include?(actions.first)
70     results[actions.first]
71   else
72     success?
73   end
74 end

Private Instance Methods

actions() click to toggle source

Gets the list of actions to run. If configured to skip actions, then this will return an empty collection.

    # File lib/state_machine/transition_collection.rb
101 def actions
102   empty? ? [nil] : map {|transition| transition.action}.uniq
103 end
catch_exceptions() { || ... } click to toggle source

Wraps the given block with a rescue handler so that any exceptions that occur will automatically result in the transition rolling back any changes that were made to the object involved.

    # File lib/state_machine/transition_collection.rb
167 def catch_exceptions
168   begin
169     yield
170   rescue Exception
171     rollback
172     raise
173   end
174 end
object() click to toggle source

Gets the object being transitioned

   # File lib/state_machine/transition_collection.rb
95 def object
96   first.object
97 end
persist() click to toggle source

Transitions the current value of the object's states to those specified by each transition

    # File lib/state_machine/transition_collection.rb
138 def persist
139   each {|transition| transition.persist}
140 end
reset() click to toggle source

Resets any information tracked from previous attempts to perform the collection

    # File lib/state_machine/transition_collection.rb
114 def reset
115   @results = {}
116   @success = false
117 end
rollback() click to toggle source

Rolls back changes made to the object's states via each transition

    # File lib/state_machine/transition_collection.rb
160 def rollback
161   each {|transition| transition.rollback}
162 end
run_actions() { || ... } click to toggle source

Runs the actions for each transition. If a block is given method, then it will be called instead of invoking each transition's action.

The results of the actions will be used to determine success?.

    # File lib/state_machine/transition_collection.rb
146 def run_actions
147   catch_exceptions do
148     @success = if block_given?
149       result = yield
150       actions.each {|action| results[action] = result}
151       !!result
152     else
153       actions.compact.each {|action| !skip_actions && results[action] = object.send(action)}
154       results.values.all?
155     end
156   end
157 end
run_callbacks(index = 0, &block) click to toggle source

Runs each transition's callbacks recursively. Once all before callbacks have been executed, the transitions will then be persisted and the configured actions will be run.

If any transition fails to run its callbacks, :halt will be thrown.

    # File lib/state_machine/transition_collection.rb
124 def run_callbacks(index = 0, &block)
125   if transition = self[index]
126     throw :halt unless transition.run_callbacks(:after => !skip_after) do
127       run_callbacks(index + 1, &block)
128       {:result => results[transition.action], :success => success?}
129     end
130   else
131     persist
132     run_actions(&block)
133   end
134 end
success?() click to toggle source

Did each transition perform successfully? This will only be true if the following requirements are met:

  • No before callbacks halt

  • All actions run successfully (always true if skipping actions)

   # File lib/state_machine/transition_collection.rb
90 def success?
91   @success
92 end
use_event_attributes?() click to toggle source

Determines whether an event attribute be used to trigger the transitions in this collection or whether the transitions be run directly outside of the action.

    # File lib/state_machine/transition_collection.rb
108 def use_event_attributes?
109   !skip_actions && !skip_after && actions.all? && actions.length == 1 && first.machine.action_hook?
110 end
valid?() click to toggle source

Is this a valid set of transitions? If the collection was creating with any false values for transitions, then the the collection will be marked as invalid.

   # File lib/state_machine/transition_collection.rb
82 def valid?
83   @valid
84 end
within_transaction() { || ... } click to toggle source

Runs a block within a transaction for the object being transitioned. If transactions are disabled, then this is a no-op.

    # File lib/state_machine/transition_collection.rb
178 def within_transaction
179   if use_transaction && !empty?
180     first.within_transaction do
181       yield
182       success?
183     end
184   else
185     yield
186   end
187 end