module StateMachine::InstanceMethods

Public Instance Methods

fire_events(*events) click to toggle source

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

  • Before callbacks

  • Persist state

  • Invoke action

  • After callbacks

For example, if two events (for state machines A and B) are run in parallel, the order in which steps are run is:

  • A - Before transition callbacks

  • B - Before transition callbacks

  • A - Persist new state

  • B - Persist new state

  • A - Invoke action

  • B - Invoke action (only if different than A’s action)

  • A - After transition callbacks

  • B - After transition callbacks

Note that multiple events on the same state machine / attribute cannot be run in parallel. If this is attempted, an ArgumentError will be raised.

Halting callbacks ↑

When running multiple events in parallel, special consideration should be taken with regard to how halting within callbacks affects the flow.

For before callbacks, any :halt error that’s thrown will immediately cancel the perform for all transitions. As a result, it’s possible for one event’s transition to affect the continuation of another.

On the other hand, any :halt error that’s thrown within an after callback with only affect that event’s transition. Other transitions will continue to run their own callbacks.

Example ↑

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

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

  state_machine :alarm_state, :namespace => 'alarm', :initial => :on do
    event :enable do
      transition all => :active
    end

    event :disable do
      transition all => :off
    end
  end
end

vehicle = Vehicle.new                         # => #<Vehicle:0xb7c02850 @state="parked", @alarm_state="active">
vehicle.state                                 # => "parked"
vehicle.alarm_state                           # => "active"

vehicle.fire_events(:ignite, :disable_alarm)  # => true
vehicle.state                                 # => "idling"
vehicle.alarm_state                           # => "off"

# If any event fails, the entire event chain fails
vehicle.fire_events(:ignite, :enable_alarm)   # => false
vehicle.state                                 # => "idling"
vehicle.alarm_state                           # => "off"

# Exception raised on invalid event
vehicle.fire_events(:park, :invalid)          # => StateMachine::InvalidEvent: :invalid is an unknown event
vehicle.state                                 # => "idling"
vehicle.alarm_state                           # => "off"
    # File lib/state_machine/extensions.rb
102 def fire_events(*events)
103   self.class.state_machines.fire_events(self, *events)
104 end
fire_events!(*events) click to toggle source

Run one or more events in parallel. If any event fails to run, then a StateMachine::InvalidTransition exception will be raised.

See StateMachine::InstanceMethods#fire_events for more information.

Example ↑

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

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

  state_machine :alarm_state, :namespace => 'alarm', :initial => :active do
    event :enable do
      transition all => :active
    end

    event :disable do
      transition all => :off
    end
  end
end

vehicle = Vehicle.new                         # => #<Vehicle:0xb7c02850 @state="parked", @alarm_state="active">
vehicle.fire_events(:ignite, :disable_alarm)  # => true

vehicle.fire_events!(:ignite, :disable_alarm) # => StateMachine::InvalidTranstion: Cannot run events in parallel: ignite, disable_alarm
    # File lib/state_machine/extensions.rb
139 def fire_events!(*events)
140   run_action = [true, false].include?(events.last) ? events.pop : true
141   fire_events(*(events + [run_action])) || raise(StateMachine::InvalidParallelTransition.new(self, events))
142 end