ruby-on-rails - 使用 pluginaweek 的 state_machine,我可以在事件期间引用 activerecord 对象吗?

标签 ruby-on-rails rubygems state-machine

我正在尝试实现将对象转换为 :suspended 状态的“挂起”事件。但我需要能够“取消暂停”,并返回到之前的状态。我在模型中添加了一个 previous_state 字段,但我看不到如何在事件 block 中访问它。

这是我试图实现的基本逻辑:

event :suspend do
  owner.previous_state = self.state
  transition [:new, :old] => :suspended
end

event :unsuspend do
  transition :suspended => owner.previous_state.to_sym
  owner.previous_state = nil
end

state_machine 文档不是很有帮助,我在网上找不到示例。有时很难知道如何向谷歌描述一些东西:)

最佳答案

state_machine 的作者在这里也提供了一个替代方案:https://groups.google.com/d/msg/pluginaweek-talk/LL9VJdL_x9c/vP1qv6br734J

以机智:

另一种可能的解决方案是对状态机的工作方式有一点创造性。 ORM 中有很多钩子(Hook),例如 ActiveRecord,它们使我们能够在流程的任何阶段设置状态。考虑以下:

class Vehicle < ActiveRecord::Base
  before_validation do |vehicle|
    # Set the actual value based on the previous state if we've just restored
    vehicle.state = vehicle.previous_state if vehicle.restored?
  end

  state_machine :initial => :parked do
    event :ignite do
      transition :parked => :idling
    end

    event :restore do
      transition any => :restored
    end

    state :parked do
      validates_presence_of :name
    end
  end

  # Look up previous state here...
  def previous_state
    'parked'
  end
end

在这个例子中,一个新的状态,restored,被引入了,尽管它实际上并没有被持久化到数据库中。相反,我们提供了一个 before_validation Hook ,它根据先前的状态重写状态。你可以看到下面的结果:
v = Vehicle.new(:name => 'test')  # => #<Vehicle id: nil, name: "test", state: "parked">
v.save                            # => true
v.name = nil                      # => nil
v.ignite                          # => true
v                                 # => #<Vehicle id: 1, name: nil, state: "idling">
v.restore                         # => false
v.errors                          # => #<OrderedHash {:name=>["can't be blank"]}>
v.state                           # => "idling"
v.name = 'test'                   # => "test"
v.restore                         # => true
v                                 # => #<Vehicle id: 1, name: "test", state: "parked">
v.parked?                         # => true

这应该需要更少的数据库命中,因为它发生在验证之前。在我的情况下,完整的图片如下所示:
module Interpreting::Status

  extend ActiveSupport::Concern

  included do

    before_validation :restore_previous_state, if: :interpreter_cancelled?

    state_machine :state, :initial => :ordered do

      before_transition :to => :interpreter_booked, :do => :set_previous_state

      state :ordered

      state :confirmed

      state :interpreter_booked

      state :interpreter_cancelled # Transient status
    end

  end


protected

  def set_previous_state
    self.previous_state = self.state
  end

  def restore_previous_state
    self.state = self.previous_state
  end

end

关于ruby-on-rails - 使用 pluginaweek 的 state_machine,我可以在事件期间引用 activerecord 对象吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5807374/

相关文章:

ruby-on-rails - Rails chartkick 堆积条形图

ruby-on-rails - 为什么bundler不安装JSON gem?

rubygems - Gemfile.lock 生成 BUNDLED WITH

controls - Petri网和有限状态机有什么区别?

workflow - 使用状态机模式可以实现并行拆分工作流吗?

ruby-on-rails - 需要更改什么才能在 Linux 中运行在 Windows 上创建的 Rails 应用程序?

ruby-on-rails - 不正确的 rake 版本

ruby-on-rails - Rails 如何配置 rspec 这样你就不需要 require "rails_helper"

ruby - 如何让 Ruby 找到原生库?

amazon-web-services - 状态机忽略阶跃函数错误