A transition represents a state change for a specific attribute.
Transitions consist of:
An event
A starting state
An ending state
The arguments passed in to the event that triggered the transition (does
not include the run_action
boolean argument if specified)
The original state value before the transition
The state machine for which this transition is defined
The object being transitioned
The result of invoking the action associated with the machine
The new state value after the transition
Whether the transition is only existing temporarily for the object
Determines equality of transitions by testing whether the object, states, and event involved in the transition are equal
# File lib/state_machine/transition.rb, line 313 def ==(other) other.instance_of?(self.class) && other.object == object && other.machine == machine && other.from_name == from_name && other.to_name == to_name && other.event == event end
The action that will be run when this transition is performed
# File lib/state_machine/transition.rb, line 109 def action machine.action end
The attribute which this transition's machine is defined for
# File lib/state_machine/transition.rb, line 104 def attribute machine.attribute end
A hash of all the core attributes defined for this transition with their names as keys and values of the attributes as values.
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 185 def attributes @attributes ||= {:object => object, :attribute => attribute, :event => event, :from => from, :to => to} end
The event that triggered the transition
# File lib/state_machine/transition.rb, line 114 def event @event.name end
The state name before the transition
# File lib/state_machine/transition.rb, line 129 def from_name @from_state.name end
The human-readable name of the event that triggered the transition
# File lib/state_machine/transition.rb, line 124 def human_event @event.human_name(@object.class) end
The human-readable state name before the transition
# File lib/state_machine/transition.rb, line 139 def human_from_name @from_state.human_name(@object.class) end
The new human-readable state name after the transition
# File lib/state_machine/transition.rb, line 154 def human_to_name @to_state.human_name(@object.class) end
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 328 def inspect "#<#{self.class} #{%w(attribute event from from_name to to_name).map {|attr| "#{attr}=#{send(attr).inspect}"} * ' '}>" end
Does this transition represent a loopback (i.e. the from and to state are the same)
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 166 def loopback? from_name == to_name end
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
.
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 transition.perform(Time.now) # => Passes in additional arguments and runs the +save+ action transition.perform(Time.now, false) # => Passes in additional arguments and only sets the state attribute
# File lib/state_machine/transition.rb, line 207 def perform(*args) run_action = [true, false].include?(args.last) ? args.pop : true self.args = args # Run the transition !!TransitionCollection.new([self], :actions => run_action).perform end
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.
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 268 def persist unless @persisted machine.write(object, :state, to) @persisted = true end end
The fully-qualified name of the event that triggered the transition
# File lib/state_machine/transition.rb, line 119 def qualified_event @event.qualified_name end
The fully-qualified state name before the transition
# File lib/state_machine/transition.rb, line 134 def qualified_from_name @from_state.qualified_name end
The new fully-qualified state name after the transition
# File lib/state_machine/transition.rb, line 149 def qualified_to_name @to_state.qualified_name end
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 306 def reset @before_run = @persisted = @after_run = false @paused_block = nil end
Rolls back changes made to the object's state via this transition. This
will revert the state back to the from
value.
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 299 def rollback reset machine.write(object, :state, from) end
Runs the before / after callbacks for this transition. If a block is provided, then it will be executed between the before and after callbacks.
Configuration options:
before
- Whether to run before callbacks.
after
- Whether to run after callbacks. If false, then any
around callbacks will be paused until called again with after
enabled. Default is true.
This will return true if all before callbacks gets executed. After callbacks will not have an effect on the result.
# File lib/state_machine/transition.rb, line 235 def run_callbacks(options = {}, &block) options = {:before => true, :after => true}.merge(options) @success = false halted = pausable { before(options[:after], &block) } if options[:before] # After callbacks are only run if: # * An around callback didn't halt after yielding # * They're enabled or the run didn't succeed after if !(@before_run && halted) && (options[:after] || !@success) @before_run end
The new state name after the transition
# File lib/state_machine/transition.rb, line 144 def to_name @to_state.name end
Is this transition existing for a short period only? If this is set, it indicates that the transition (or the event backing it) should not be written to the object if it fails.
# File lib/state_machine/transition.rb, line 173 def transient? @transient end
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 218 def within_transaction machine.within_transaction(object) do yield end end