= Travis Build Status
{}[http://travis-ci.org/troessner/transitions]
= Synopsis
transitions is a ruby state machine implementation.
= Installation
== Rails
This goes into your Gemfile:
gem "transitions", :require => ["transitions", "active_model/transitions"]
… and this into your ORM model:
include ActiveModel::Transitions
== Standalone
gem install transitions
= Using transitions
class Product
include ActiveModel::Transitions
state_machine do
state :available # first one is initial state
state :out_of_stock, :exit => :exit_out_of_stock
state :discontinued, :enter => lambda { |product| product.cancel_orders }
event :discontinued do
transitions :to => :discontinued, :from => [:available, :out_of_stock], :on_transition => :do_discontinue
end
event :out_of_stock do
transitions :to => :out_of_stock, :from => [:available, :discontinued]
end
event :available do
transitions :to => :available, :from => [:out_of_stock], :guard => lambda { |product| product.in_stock > 0 }
end
end
end
In this example we assume that you are in a rails project using Bundler, which would automitcally require `transitions`.
If this is not the case for you you have to add
require 'transitions'
whereever you load your dependencies in your application.
= Features
== Events
When you declare an event, say discontinue, two methods are declared for
you: discontinue and discontinue!. Both events will modify the state attribute on successful transition,
but only the bang(!)-version will call save!.
== Automatic scope generation
transitions will automatically generate scopes for you if you are using ActiveRecord and tell it to do so via the auto_scopes option:
Given a model like this:
class Order < ActiveRecord::Base
include ActiveModel::Transitions
state_machine :auto_scopes => true do
state :pick_line_items
state :picking_line_items
end
end
you can use this feature a la:
>> Order.pick_line_items
=> []
>> Order.create!
=> #
>> Order.pick_line_items
=> [#]
== Using on_transition
Each event definition takes an optional "on_transition" argument, which allows you to execute methods on transition.
You can pass in a Symbol, a String, a Proc or an Array containing method names as Symbol or String like this:
event :discontinue do
transitions :to => :discontinued, :from => [:available, :out_of_stock], :on_transition => [:do_discontinue, :notify_clerk]
end
== Using success
In case you need to trigger a method call after a successful transition you can use success:
event :discontinue, :success => :notfiy_admin do
transitions :to => :discontinued, :from => [:available, :out_of_stock]
end
In addition to just specify the method name on the record as a symbol you can pass a lambda to
perfom some more complex success callbacks:
event :discontinue, :success => lambda { |order) AdminNotifier.notify_about_discontinued_order(order) } do
transitions :to => :discontinued, :from => [:available, :out_of_stock]
end
== Timestamps
If you'd like to note the time of a state change, Transitions comes with timestamps free!
To activate them, simply pass the :timestamp option to the event definition with a value of either true or
the name of the timestamp column.
*NOTE - This should be either true, a String or a Symbol*
# This will look for an attribute called exploded_at or exploded_on (in that order)
# If present, it will be updated
event :explode, :timestamp => true do
transitions :from => :complete, :to => :exploded
end
# This will look for an attribute named repaired_on to update upon save
event :rebuild, :timestamp => :repaired_on do
transitions :from => :exploded, :to => :rebuilt
end
== `event_fired` and `event_failed`
In case you define `event_fired` and / or `event_failed`, `transitions` will use those callbacks correspondingly.
You can use those callbacks like this:
def event_fired(current_state, new_state, event)
MyLogger.info "Event fired #{event.inspect}"
end
def event_failed(event)
MyLogger.warn "Event failed #{event.inspect}"
end
== Listing all the available states
You can easily get a listing of all available states:
Order.available_states # Uses the default state machine
# => [:pick_line_items, :picking_line_items]
In case you have multiple state machines you can also pass the state machine name:
Order.available_states(:your_machine)
= Documentation, Guides & Examples
- {Online API Documentation}[http://rdoc.info/github/troessner/transitions/master/Transitions]
= Copyright
Copyright (c) 2010 Jakub Kuźma, Timo Rößner. See LICENSE for details.