class Job
include AASM
aasm do
state :sleeping, :initial => true
state :running
state :cleaning
event :run do
transitions :from => :sleeping, :to => :running
end
event :clean do
transitions :from => :running, :to => :cleaning
end
event :sleep do
transitions :from => [:running, :cleaning], :to => :sleeping
end
end
end
class Job
include AASM
aasm do
state :sleeping, :initial => true, :before_enter => :do_something
state :running
event :run, :after => :notify_somebody do
transitions :from => :sleeping, :to => :running, :after => Proc.new {|*args| set_process(*args) } do
before do
log('Preparing to run')
end
end
end
event :sleep do
after do
...
end
error do |e|
...
end
transitions :from => :running, :to => :sleeping
end
end
def set_process(name)
...
end
def do_something
...
end
def notify_somebody(user)
...
end
end
begin
event before
event guards
transition guards
old_state before_exit
old_state exit
transition after
new_state before_enter
new_state enter
...update state...
event success # if persist successful
old_state after_exit
new_state after_enter
event after
rescue
event error
end
class Cleaner
include AASM
aasm do
state :idle, :initial => true
state :cleaning
event :clean do
transitions :from => :idle, :to => :cleaning, :guard => :cleaning_needed?
end
event :clean_if_needed do
transitions :from => :idle, :to => :cleaning do
guard do
cleaning_needed?
end
end
transitions :from => :idle, :to => :idle
end
end
def cleaning_needed?
false
end
end
job = Cleaner.new
job.may_clean? # => false
job.clean # => raises AASM::InvalidTransition
job.may_clean_if_needed? # => true
job.clean_if_needed! # idle
还可以设置多个警卫,当全部成功执行之后事件才会触发。
1
2
3
4
5
def walked_the_dog?; ...; end
event :sleep do
transitions :from => :running, :to => :sleeping, :guards => [:cleaning_needed?, :walked_the_dog?]
end
require 'aasm'
class Job
include AASM
aasm do
state :stage1, :initial => true
state :stage2
state :stage3
state :completed
event :stage1_completed do
transitions from: :stage1, to: :stage3, guard: :stage2_completed?
transitions from: :stage1, to: :stage2
end
end
def stage2_completed?
true
end
end
job = Job.new
job.stage1_completed
job.aasm.current_state # stage3
ActiveRecord
AASM生来就支持ActiveRecord,并且允许自动把对象的状态保存到数据库中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Job < ActiveRecord::Base
include AASM
aasm do # default column: aasm_state
state :sleeping, :initial => true
state :running
event :run do
transitions :from => :sleeping, :to => :running
end
event :sleep do
transitions :from => :running, :to => :sleeping
end
end
end
可以告诉AASM自动保存对象或者不进行保存。
1
2
3
job = Job.new
job.run # not saved
job.run! # saved
class Job < ActiveRecord::Base
include AASM
aasm :skip_validation_on_save => true do
state :sleeping, :initial => true
state :running
event :run do
transitions :from => :sleeping, :to => :running
end
event :sleep do
transitions :from => :running, :to => :sleeping
end
end
end
class Job < ActiveRecord::Base
include AASM
aasm :no_direct_assignment => true do
state :sleeping, :initial => true
state :running
event :run do
transitions :from => :sleeping, :to => :running
end
end
end
class Job < ActiveRecord::Base
include AASM
enum state: {
sleeping: 5,
running: 99
}
aasm :column => :state, :enum => true do
state :sleeping, :initial => true
state :running
end
end
class Job
include MongoMapper::Document
include AASM
key :aasm_state, Symbol
aasm do
...
end
end
自动级联
AASM会自动为每一个model的状态创建级联方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
class Job < ActiveRecord::Base
include AASM
aasm do
state :sleeping, :initial => true
state :running
state :cleaning
end
def self.sleeping
"This method name is already in use"
end
end
1
2
3
4
5
6
7
8
class JobsController < ApplicationController
def index
@running_jobs = Job.running
@recent_cleaning_jobs = Job.cleaning.where('created_at >= ?', 3.days.ago)
# @sleeping_jobs = Job.sleeping #=> "This method name is already in use"
end
end
如果你需要级联,在定义AASM状态的时候做一些设置,关闭创建行为即可,比如:
1
2
3
4
5
6
7
8
9
class Job < ActiveRecord::Base
include AASM
aasm :create_scopes => false do
state :sleeping, :initial => true
state :running
state :cleaning
end
end
class Job < ActiveRecord::Base
include AASM
aasm do
state :sleeping, :initial => true
state :running
event :run, :after_commit => :notify_about_running_job do
transitions :from => :sleeping, :to => :running
end
end
def notify_about_running_job
...
end
end
class Job < ActiveRecord::Base
include AASM
aasm :column => 'my_state' do
...
end
end
无论使用什么列名,确保为此次列名的修改创建一个migration(列的类型为string):
1
2
3
4
5
6
7
8
9
class AddJobState < ActiveRecord::Migration
def self.up
add_column :jobs, :aasm_state, :string
end
def self.down
remove_column :jobs, :aasm_state
end
end
检查
AASM支持一些方法用来找出提供或禁止了哪些状态或事件。
给定一个Job类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# show all states
Job.aasm.states.map(&:name)
=> [:sleeping, :running, :cleaning]
job = Job.new
# show all permitted (reachable / possible) states
job.aasm.states(:permitted => true).map(&:name)
=> [:running]
job.run
job.aasm.states(:permitted => true).map(&:name)
=> [:cleaning, :sleeping]
# show all possible (triggerable) events (allowed by transitions)
job.aasm.events.map(&:name)
=> [:sleep]