What is transitions?
transitions is a ruby state machine implementation based on Rick Olson’s ActiveModel::StateMachine. It was extracted from ActiveModel and turned into a gem when it got the axe in commit db49c706b.
I really encourage you to try state_machine before using this gem. Currently I have no time to maintain the gem, if you want to add some new features - contact with me.
Quick Example
require 'transitions'
class Product
include 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
Automatic scope generation
‘transitions` will automatically generate scopes for you if you are using AR:
Given a model like this:
class Order < ActiveRecord::Base
include ActiveRecord::Transitions
state_machine 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 id: 3, state: "pick_line_items", description: nil, created_at: "2011-08-23 15:48:46", updated_at: "2011-08-23 15:48:46">
>> Order.pick_line_items
=> [#<Order id: 3, state: "pick_line_items", description: nil, created_at: "2011-08-23 15:48:46", updated_at: "2011-08-23 15:48:46">]
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
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
transiions :from => :exploded, :to => :rebuilt
end
Using with Rails
This goes into your Gemfile:
gem "transitions", :require => ["transitions", "active_record/transitions"]
… and this into your AR model:
include ActiveRecord::Transitions
A note about persistence
The property used to persist the models’ state is named state
(really!), which should be a string column wide enough to fit your longest state name. It should also be mentioned that #save!
is called after every successful event.
Event execution flow
On an event, with our quick example product going from :available
to :discontinued
it looks like this:
-
baby_ninja.discontinue!(:reason => :pirates)
-
call
:exit
handler of:available
state -
call
:guard
of:available to :discontinue
transition within#discontinue
event -
call
#event_failed(:event)
and abort unless3.
returnedtrue
-
call
:on_transition(:reason => :pirates)
of:available to :discontinue
transition within#discontinue
event -
call
:enter
handler of:discontinue
-
call
#event_fired(:available, :discontinue)
-
call
#write_state(machine, :discontinue)
-
call
#write_state_without_persistence(machine, :discontinue)
-
call
baby_ninja#:success
handler method of#discontinue
event
A note about events
When you declare an event discontinue
, two methods are declared for you: discontinue
and discontinue!
. Both events will call write_state_without_persistence
on successful transition, but only the bang(!)-version will call write_state
.
Documentation, Guides & Examples
Copyright
Copyright © 2010 Jakub Kuźma, Timo Rößner. See LICENSE for details.