0

我目前正在开发一个 Rails 应用程序,我正在使用 state_machine gem 来指导客户完成一个复杂的过程。

在流程的多个状态下,我需要在一段时间后触发事件。例如,如果客户在 5 天后仍未确认收到订单,我想自动向他发送一封电子邮件并进入包裹跟踪流程。

class Order < ActiveRecord::Base



    state_machine :initial => :confirmed do

        after_transition :on => :not_received_by_5_days, do |order, transition|
            order.send_email
            order. .....
            order. .....

        event :customer_confirmation do
            transition :confirmed => :order_received
        end

        event :not_received_by_5_days do
            transition :confirmed => :parcel_tracking_process
        end

        def send_email
            blabla
        end
    end

end

在测试我以前的解决方案后进行编辑:

如何在一段时间后触发转换?

谢谢,

克莱门特

4

2 回答 2

0

作为另一种选择,state_manager( https://github.com/ghempton/state_manager ) gem 与 delayjob 集成,并允许在一段时间后自动触发转换:

class UserStates < StateManager::Base
  state :submitted do
    event :activate, :transitions_to => :active, :delay => 2.days
  end

  state :active
end
于 2013-11-28T15:31:19.233 回答
0

要将解决方案分为两大类,您可以:

  1. 使用 Ruby/Rails 队列解决方案,例如DelayedJobResqueSidekiq;或者,
  2. 使用定时任务。

如果您已经在使用其中一种工具或知道您最终将使用其中一种工具,则前者往往最有意义。所有这些都需要相当大的努力才能开始。Resque 和 Sidekiq 需要配置 Redis 服务器,而 DelayedJob 使用您现有的数据库。Resque 还需要一个插件来调度作业,而 DelayedJob 和 Sidekiq 原生支持调度作业。所有这三个都需要创建作业模型并配置工作人员以运行。

假设您具有 cron 访问权限,后者非常简单。用 Ruby 编写一个脚本,并安排它通过 cron 自动运行。

我已经有一段时间没有使用 state_machine 了,但这应该可以工作(如果没有,它会理解这个想法):

#!/usr/bin/env /path/to/project/bin/rails runner
Order.where(state: 'confirmed').where("created_at <= #{5.days.ago}").find_each do |o|
  o.not_received_by_5_days
end

这里发生了什么?一旦我们的 Order 对象被创建,它就会进入confirmed状态。因此,要找到需要一点点推动的订单,我们可以运行 ActiveRecord 查询来查找confirmed状态为 5 天以上的订单。然后我们遍历每条记录并触发 not_received_by_5_days 事件。

整个事情由 Rails 运行程序管理,它加载您的 Rails 环境并在那里执行您的脚本代码(就像使用 Rails 控制台一样,但无需人工干预)。

每天由 cron 运行一次或两次(如果您希望电子邮件更频繁地发出,则更频繁地运行),该脚本将找到至少 5 天前的每个无人看管的订单,并将其移动到您的工作流程中。由于一旦 not_received_by_5_days 事件触发,您的代码(应该)将人们转移到新状态,因此他们将不再出现在后续脚本执行中,并且只会收到一个提醒。

于 2013-07-30T20:23:25.293 回答