我目前正在开发一个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
在测试我之前的解决方案后进行编辑:
如何在一段时间后触发过渡?
谢谢,
克莱门特
答案 0 :(得分:0)
要将解决方案分为两大类,您可以:
如果您已经使用其中一种工具或者知道您最终会使用其中一种工具,前者往往最有意义。所有这些都需要相当大的努力才能开始。当DelayedJob使用您现有的数据库时,Resque和Sidekiq需要配置Redis服务器。 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查询以查找5天以上confirmed
状态的订单。然后,我们遍历每条记录并触发not_received_by_5_days事件。
整个过程由Rails运行管理,它加载你的Rails环境并在那里执行你的脚本代码(就像使用Rails控制台一样,但没有人工干预)。
每天由cron运行一次或两次(如果您希望电子邮件更频繁地运行,则更频繁地运行),脚本将找到至少5天的每个无人注意的订单并将其移动到您的工作流程中。由于您的代码(应该)在not_received_by_5_days事件触发后将人员移动到新状态,因此它们将不再显示在后续脚本执行中,并且只会收到一个提醒。
答案 1 :(得分:0)
作为另一个选项,state_manager(https://github.com/ghempton/state_manager)gem与delayedjob集成,并允许在一段时间后自动通过触发转换:
class UserStates < StateManager::Base
state :submitted do
event :activate, :transitions_to => :active, :delay => 2.days
end
state :active
end