2. What is a workflow?
A process that moves through a
sequence of steps (from start and
finish) in order to perform
some function
3. Examples
Fulfilling an order
●
Publishing documents / content
●
Approving a request
●
4. A few things in common ...
Typically multi-step
●
Performed asynchronously
●
May be long-running
●
Steps may be conditional
●
Each step may need to do an operation
●
5. The Idea
Many simple workflows
can be modelled as a
finite state machine
(Not all)
6. acts_as_state_machine
AASM to friends!
●
Rails plugin by Scott Barron
●
Provides:
●
A simple FSM implementation
●
A DSL for expressing FSM in Ruby code
●
8. # Basic workflow example
class ActionWorkflow < ActiveRecord::Base
acts_as_state_machine :initial => :created,
:column => 'status'
state :created
state :approved
state :rejected
state :cancelled
event :approve { transitions :to => :approved, :from
=> :created }
event :cancel { transitions :to => :cancelled, :from
=>[:created, :approved, :rejected] }
...
end
9. AASM provides some methods
An action! method for each event
●
A query? method for each state
●
Examples:
workflow.approve! # moves to approved state
workflow.cancelled? # Returns boolean
10. Guards
event :approve { transitions :to => :approved, :from
=> :created, :guard => Proc.new {|w| !w.expired?}}
Allows conditions on transitions
●
Transition is not available unless
●
condition is met
Some conditions may be expressed
●
best in your code, not in guards
11. Callbacks
state :approved, :after => :on_submit
state :approved, :after => :Proc.new {|m| m.abc }
Available hooks :enter, :after and :exit
●
Callbacks provide a way to do some
●
operation when a transition occurs
def on_submit
record_action
...
end
12. Other useful stuff
# Fire your actions (cleanly)
attr_accessor :action
def action_workflow
eval(quot;self.#{self.action}!quot;) unless self.action.nil?
end
# Add an audit trail ...
has_many :actions, :class_name => quot;WorkflowActionquot;
def record_action
self.actions << WorkflowAction.create(
:comment => self.comment, :actioner_id =>
self.acting_person, :state => self.state)
end
13. A few caveats
A minor change to AASM .rb required
●
Avoids runtime error (on 1.2.3 anyway!)
●
Also added a couple of things locally
●
Lourens Naude's method (mis-named)
●
A corrected next_events_for_current_state
●
Ask me for the patch if you're keen
●
14. # Retrieves next states for current state
def next_events_for_current_state
events = []
self.class.read_inheritable_attribute(
:transition_table).each do |key, value|
value.each do |transition|
events << key if transition.from ==
current_state()
end
end
events
end
15. Remarks
AASM makes it very simple to implement
a simple workflow model
A full workflow system is more complex
●
acts_as_coloured_petri_net :)
●
Piston is your friend ... especially when
●
making local modifications to plugins
16. Parting thought
Q: What are the three most important
ideas in programming?
1. Abstraction
2. Abstraction
3. Abstraction
(Hudak, 2000)