ruby-on-rails - 在 AASM 中自动更改状态的最佳方法是什么

标签 ruby-on-rails ruby state-machine aasm

我一直在使用 AASM在我当前的项目中制作状态机,想知道自动调用事件并进入下一个状态的最佳方式是什么?

我正在考虑两种方法:

  1. 设置后台作业以定期检查是否满足某些条件,从而调用事件以进入下一个状态。

  2. before_save 调用一个连续尝试下一个事件的方法。有了守卫,如果满足条件,它就不会成功,否则,状态会改变,下次更新模型时,我们会检查新事件。

我倾向于第二个选项,因为设置一个 background_job 队列只是为了转换事件似乎有点矫枉过正。我找不到这方面的最佳做法,所以我很想知道最好的方法以及为什么会这样?

Example

例如,我们有 start_onboardingcomplete_onboarding 事件。我不想手动调用这些事件,但我想在 pending -> in_progress -> completed 事件之间自动转换。

  enum status: {
    pending: 1,
    in_progress: 2,
    completed: 3
  }

  aasm column: :status, enum: true, whiny_transitions: false do
    state :pending, initial: true
    state :in_progress
    state :completed

    event :start_onboarding do
      transitions from: :pending, to: :in_progress
    end

    event :complete_onboarding do
      transitions from: :in_progress,
                  to: :completed,
                  if: :onboarding_completed?
    end
  end

最佳答案

在类似的任务中:

我们摆脱了:

  • 切换状态的回调,因为它们会降低性能
  • 实时轮询(带后台作业),因为它也会降低性能

我们开始使用:

代码看起来像这样:

require 'active_record'
require 'aasm'
require 'sidekiq'

class Task < ActiveRecord::Base
  include AASM

  establish_connection adapter: 'sqlite3', database: 'todo.db'

  connection.create_table table_name, force: true do |t|
    t.string   :name,       null: false
    t.string   :aasm_state, null: false, index: true
    t.datetime :expired_at, null: false
  end

  validates :name, :aasm_state, :expired_at, presence: true

  aasm do
    state :pending, initial: true
    state :in_progress
    state :completed
    state :expired

    event :run do
      transitions to: :in_progress
    end

    event :complete do
      transitions to: :completed
    end

    event :expire do
      transitions to: :expired, unless: :completed?
    end
  end
end

class Task::ExpireJob
  include Sidekiq::Worker

  def perform task
    task.expire!
  end
end

class Task::CreationService
  def self.create! params
    task = Task.create! params
    task.run!
    Task::ExpireJob.perform_at task.expired_at, task
    task
  end

  def self.complete! task
    task.complete!
    task
  end
end

task = Task::CreationService.create! \
  name:       'first',
  expired_at: DateTime.now + 30.seconds

p task
p Task::CreationService.complete! task

关于ruby-on-rails - 在 AASM 中自动更改状态的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42255544/

相关文章:

ruby - 从 Heroku 恢复本地数据库后的 ActiveRecord::PendingMigrationError

ruby-on-rails - 模型- View - Controller 是否与人工智能和行为树很好地配合?

ruby-on-rails - 为登录用户设计忘记密码

ruby-on-rails - sidekiq 在线程之间共享变量

ruby-on-rails - 为 Rails 标记垃圾邮件或不当内容的脚本

ruby - 如何使用 watir 滚动网页

sql - Rails ActiveRecord where 或子句

ruby-on-rails - ruby/rails : what is the right way to refer to some_user. user_profile.name 如果用户可能还没有 user_profile?

c - c中状态机的问题

design-patterns - 状态机和状态模式的实现有什么区别?