Module: OpenLoam::Workflow

Extended by:
ActiveSupport::Concern
Included in:
PendingAction
Defined in:
lib/open_loam/workflow.rb

Overview

Declarative state machine for a tenant-scoped entity: the states a record can be in, the legal moves between them, and who may make each move.

class PurchaseOrder < OpenLoam::TenantRecord
include OpenLoam::Workflow

workflow :status, initial: "draft" do
  state "draft"
  state "pending_approval"
  state "approved"

  transition :submit,  from: "draft",            to: "pending_approval"
  transition :approve, from: "pending_approval", to: "approved", roles: [:manager]
end
end

order.submit!                         # draft -> pending_approval, publishes
                                    # "<domain>.purchase_order.submit"
order.workflow_transitions_available  # => [:approve] for a manager, [] for anyone else
PurchaseOrder.open_loam_workflow           # the frozen definition, for agents and admin UI

What this buys over hand-rolled if status == "draft": an illegal move raises instead of silently writing a bad value, the roles that may move a record are declared in one readable place instead of scattered across controllers, and the whole machine is introspectable.

The state change itself is an ordinary attribute write, so OpenLoam::Auditable records it like any other change — a workflow adds no second audit trail.

Defined Under Namespace

Classes: Builder, Definition, Transition

Instance Method Summary collapse

Instance Method Details

#open_loam_workflow_state ⇒ Object



182
183
184
# File 'lib/open_loam/workflow.rb', line 182

def open_loam_workflow_state
  self[self.class.open_loam_workflow.column].to_s
end

#workflow_transitions_available ⇒ Object

Transition names that are legal right now: from this record's state, for the actor in OpenLoam::Current. Never raises — an admin screen asks this to decide which buttons to render.



174
175
176
177
178
179
180
# File 'lib/open_loam/workflow.rb', line 174

def workflow_transitions_available
  role = open_loam_workflow_role

  self.class.open_loam_workflow.transitions_from(open_loam_workflow_state)
      .select { |transition| transition.roles.empty? || transition.roles.include?(role) }
      .map(&:name)
end