state
Definition
States of a machine are automatically inferred from:
- Initial state
- State behaviors
- Event transitions (
:to
,:from
, and:except_from
options) - Transition callbacks (
:to
,:from
,:except_to
, and:except_from
options)
States never referenced must be added using
:state
or:other_states
helpers
Options
:value
- actual value to store when an object transitions to the state
- Default: name (stringified)
:if
- Determines whether an object's value matches the state (e.g.
:value => lambda {Time.now}, :if => lambda {|state| !state.nil?})
- Default: the configured value is matched
:human_name
- human-readable version of this state's name
- Default: stringifies the name and converts underscores to spaces
:cache
- If a dynamic value (via a lambda block) is being used, then setting this to true will cache the evaluated result
Helper Methods
Predicate Method ?
When a new state is defined, a predicate instance method for it is generated on the class
class Vehicle state_machine :initial => :parked do event :ignite do transition all => :idling end end end # if not already defined, This implicitly generates: class Vehicle def parked? ... end def idling? ... end
Each predicate method returns
true
if it matches the object's current state,false
otherwise
Scopes
- Each state defined on the model generates a
scope
for use to filter records with that state - Generated scopes are equivalent to:
Vehicle.with_state(:parked) # => All vehicles where the state is parked
Vehicle.with_states(:parked, :idling) # => All vehicles where the state is either parked or idling
Vehicle.without_state(:parked) # => All vehicles where the state is *not* parked
Vehicle.without_states(:parked, :idling) # => All vehicles where the state is *not* parked or idling
If class methods already exist with those names (i.e.
:with_state
,:with_states
,:without_state
, or:without_states
), then a scope will not be defined for that name. ```ruby class Vehicle < ActiveRecord::Base named_scope :with_states, lambda {|*states| {:conditions => {:state => states}}}# with_states also aliased to `with_state`
named_scope :without_states, lambda {|*states| {:conditions => ['state NOT IN (?)', states]}}
# without_states also aliased to `without_state`
end
> States are converted to their stored values before being passed to the query
- Scopes can be chained:
```ruby
Vehicle.with_state(:parked).all(:order => 'id DESC')