You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用YAML动态创建可配置状态机?Rails员工离职工作流需求

基于YAML配置的动态离职工作流实现方案(Rails)

针对多组织专属的动态状态机需求,直接用aasm的静态定义确实受限,下面提供一套灵活的自定义实现方案,支持从YAML加载组织专属配置,动态处理状态转换。

一、设计YAML配置结构

每个组织的离职流程配置独立存储,包含状态列表、事件转换规则、触发动作、权限控制等核心信息:

# 示例:某组织的离职流程配置
states:
  - initiated          # 离职申请发起
  - exit_interview_done # 离职面谈完成
  - assets_returned    # 资产归还
  - finance_approved   # 财务结清
  - finalized          # 离职完成

events:
  mark_interview_done:
    from: initiated
    to: exit_interview_done
    allowed_roles: [hr, department_manager] # 允许触发的角色
    triggers:
      - send_interview_notice_to_hr        # 触发的动作(对应服务类)
  confirm_assets_return:
    from: exit_interview_done
    to: assets_returned
    allowed_roles: [admin, hr]
  approve_finance:
    from: assets_returned
    to: finance_approved
    triggers:
      - generate_finance_clearance_doc
  finalize_termination:
    from: finance_approved
    to: finalized
    triggers:
      - deactivate_employee_account
      - send_termination_letter

二、配置存储方案

两种可选方式,根据业务需求选择:

  1. 数据库存储(推荐,支持动态修改):给Organization模型添加workflow_config字段(类型text),直接存储YAML文本。
  2. 文件系统存储:在config/organizations/下按组织slug创建子目录,存放对应YAML文件(适合需要版本控制的场景)。

三、封装动态状态机服务类

核心逻辑放在服务类中,负责加载配置、验证权限、执行状态转换和触发动作:

# app/services/dynamic_termination_workflow.rb
class DynamicTerminationWorkflow
  attr_reader :employee, :config

  def initialize(employee)
    @employee = employee
    @config = load_organization_config
  end

  # 加载组织专属配置(示例:从数据库加载)
  def load_organization_config
    raw_config = employee.organization.workflow_config
    return default_config if raw_config.blank?

    YAML.safe_load(raw_config, aliases: true) || default_config
  end

  # 兜底默认配置,防止组织未配置时出错
  def default_config
    YAML.safe_load(<<~YML)
      states:
        - initiated
        - finalized
      events:
        finalize:
          from: initiated
          to: finalized
    YML
  end

  # 检查是否允许触发指定事件
  def can_trigger?(event_name, actor)
    event = config[:events][event_name.to_sym]
    return false unless event

    current_state = employee.termination_state.to_sym
    # 检查当前状态是否在允许的转换起点
    return false unless event[:from].include?(current_state)
    # 检查角色权限(如果配置了)
    event[:allowed_roles] ? event[:allowed_roles].include?(actor.role.to_sym) : true
  end

  # 执行事件触发逻辑
  def trigger(event_name, actor)
    return false unless can_trigger?(event_name, actor)

    event = config[:events][event_name.to_sym]
    new_state = event[:to]

    # 事务保证状态转换和动作执行的原子性
    ActiveRecord::Base.transaction do
      employee.update!(termination_state: new_state)
      execute_triggers(event[:triggers], actor) if event[:triggers]
    end

    true
  rescue StandardError => e
    Rails.logger.error "Workflow trigger failed: #{e.message}"
    false
  end

  private

  # 执行事件触发的动作(调用对应服务类)
  def execute_triggers(triggers, actor)
    triggers.each do |trigger|
      service_class = "#{trigger.camelize}Service".constantize
      service_class.call(employee: employee, actor: actor)
    end
  end
end

四、在Employee模型中集成

给员工模型添加快捷方法,简化调用:

# app/models/employee.rb
class Employee < ApplicationRecord
  belongs_to :organization
  enum termination_state: -> { DynamicTerminationWorkflow.new(self).config[:states].map { |s| [s, s] }.to_h }

  def termination_workflow
    @termination_workflow ||= DynamicTerminationWorkflow.new(self)
  end

  # 快捷触发事件
  def trigger_termination_event(event_name, actor)
    termination_workflow.trigger(event_name, actor)
  end

  # 快捷检查权限
  def can_trigger_termination_event?(event_name, actor)
    termination_workflow.can_trigger?(event_name, actor)
  end
end

五、业务代码中使用示例

在控制器或业务逻辑中直接调用:

# 示例:HR标记离职面谈完成
employee = Employee.find(params[:id])
current_actor = current_user

if employee.can_trigger_termination_event?(:mark_interview_done, current_actor)
  employee.trigger_termination_event(:mark_interview_done, current_actor)
  redirect_to employee_path(employee), notice: "离职面谈已标记完成"
else
  redirect_to employee_path(employee), alert: "无权限执行此操作"
end

六、可选优化点

  1. 配置验证:添加配置格式校验逻辑,防止无效YAML导致系统出错。
  2. 配置缓存:用Rails.cache缓存组织配置,减少数据库或文件读取次数。
  3. 版本控制:给组织配置添加历史版本记录,支持回滚操作。

内容的提问来源于stack exchange,提问作者Mukul Jangid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 05:24:58