Skip to content

Repository files navigation

AASM - Ruby state machines Build StatusCode ClimateCoverage Status

This package contains AASM, a library for adding finite state machines to Ruby classes.

AASM started as the acts_as_state_machine plugin but has evolved into a more generic library that no longer targets only ActiveRecord models. It currently provides adapters for ActiveRecord and Mongoid, but it can be used for any Ruby class, no matter what parent class it has (if any).

Usage

Adding a state machine is as simple as including the AASM module and start defining states and events together with their transitions:

classJobincludeAASMaasmdostate:sleeping,:initial=>truestate:runningstate:cleaningevent:rundotransitions:from=>:sleeping,:to=>:runningendevent:cleandotransitions:from=>:running,:to=>:cleaningendevent:sleepdotransitions:from=>[:running,:cleaning],:to=>:sleepingendendend

This provides you with a couple of public methods for instances of the class Job:

job=Job.newjob.sleeping?# => truejob.may_run?# => truejob.runjob.running?# => truejob.sleeping?# => falsejob.may_run?# => falsejob.run# => raises AASM::InvalidTransition

If you don't like exceptions and prefer a simple true or false as response, tell AASM not to be whiny:

classJob
...
aasm:whiny_transitions=>falsedo
...
endendjob.running?# => truejob.may_run?# => falsejob.run# => false

Callbacks

You can define a number of callbacks for your transitions. These methods will be called, when certain criteria are met, like entering a particular state:

classJobincludeAASMaasmdostate:sleeping,:initial=>true,:before_enter=>:do_somethingstate:runningevent:run,:after=>Proc.new{ |user| notify_somebody(user)}dotransitions:from=>:sleeping,:to=>:running,:on_transition=>Proc.new{|obj, *args| obj.set_process(*args)}endevent:sleepdoafterdo
...
enderrordo |e|
...
endtransitions:from=>:running,:to=>:sleepingendenddefset_process(name)
...
enddefdo_something
...
enddefnotify_somebody(user)
...
endend

In this case do_something is called before actually entering the state sleeping, while notify_somebody is called after the transition run (from sleeping to running) is finished.

Here you can see a list of all possible callbacks, together with their order of calling:

event:beforeprevious_state:before_exitnew_state:before_enter
...updatestate...
previous_state:after_exitnew_state:after_enterevent:after

Also, you can pass parameters to events:

job=Job.newjob.run(:running,:defragmentation)

In this case the set_process would be called with :defagmentation argument.

In case of an error during the event processing the error is rescued and passed to :error callback, which can handle it or re-raise it for further propagation.

Guards

Let's assume you want to allow particular transitions only if a defined condition is given. For this you can set up a guard per transition, which will run before actually running the transition. If the guard returns false the transition will be denied (raising AASM::InvalidTransition or returning false itself):

classJobincludeAASMaasmdostate:sleeping,:initial=>truestate:runningstate:cleaningevent:rundotransitions:from=>:sleeping,:to=>:runningendevent:cleandotransitions:from=>:running,:to=>:cleaningendevent:sleepdotransitions:from=>:running,:to=>:sleeping,:guard=>:cleaning_needed?endenddefcleaning_needed?falseendendjob=Job.newjob.runjob.may_sleep?# => falsejob.sleep# => raises AASM::InvalidTransition

ActiveRecord

AASM comes with support for ActiveRecord and allows automatical persisting of the object's state in the database.

classJob < ActiveRecord::BaseincludeAASMaasmdo# default column: aasm_statestate:sleeping,:initial=>truestate:runningevent:rundotransitions:from=>:sleeping,:to=>:runningendevent:sleepdotransitions:from=>:running,:to=>:sleepingendendend

You can tell AASM to auto-save the object or leave it unsaved

job=Job.newjob.run# not savedjob.run!# saved

Saving includes running all validations on the Job class. If you want make sure the state gets saved without running validations (and thereby maybe persisting an invalid object state), simply tell AASM to skip the validations:

classJob < ActiveRecord::BaseincludeAASMaasm:skip_validation_on_save=>truedostate:sleeping,:initial=>truestate:runningevent:rundotransitions:from=>:sleeping,:to=>:runningendevent:sleepdotransitions:from=>:running,:to=>:sleepingendendend

Automatic Scopes

AASM will automatically create scope methods for each state in the model.

classJob < ActiveRecord::BaseincludeAASMaasmdostate:sleeping,:initial=>truestate:runningstate:cleaningenddefsleeping"This method name is in already use"endend
classJobsController < ApplicationControllerdefindex@running_jobs=jobs.running@recent_cleaning_jobs=jobs.cleaning.where('created_at >= ?',3.days.ago)# @sleeping_jobs = jobs.sleeping #=> "This method name is in already use"endend

Transaction support

Since version 3.0.13 AASM supports ActiveRecord transactions. So whenever a transition callback or the state update fails, all changes to any database record are rolled back.

Column name & migration

As a default AASM uses the column aasm_state to store the states. You can override this by defining your favorite column name, using :column like this:

classJob < ActiveRecord::BaseincludeAASMaasm:column=>'my_state'do
...
endend

Whatever column name is used, make sure to add a migration to provide this column (of type string):

classAddJobState < ActiveRecord::Migrationdefself.upadd_column:jobs,:aasm_state,:stringenddefself.downremove_column:jobs,:aasm_stateendend

AASM supports a couple of methods to find out which states or events are provided or permissible.

Given the Job class from above:

job=Job.newjob.aasm.states=>[:sleeping,:running,:cleaning]job.aasm.states(:permissible=>true)=>[:running]job.runjob.aasm.states(:permissible=>true)=>[:cleaning,:sleeping]job.aasm.events=>[:run,:clean,:sleep]

Manually from RubyGems.org

% gem install aasm

Or if you are using Bundler

# Gemfilegem'aasm'

Building your own gems

% rake build
% sudo gem install pkg/aasm-x.y.z.gem

Latest changes

Look at the CHANGELOG for details.

Questions?

Feel free to

Authors

Warranty

This software is provided "as is" and without any express or implied warranties, including, without limitation, the implied warranties of merchantibility and fitness for a particular purpose.

License

Copyright (c) 2006-2012 Scott Barron

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

AASM - State machines for Ruby classes

Resources

Stars

25 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors