使用pluginaweek的state_machine,我可以在事件期间引用activerecord对象吗?
我正在尝试实现一个“挂起”事件,将对象转换为:挂起状态。但我需要能够“取消暂停”,并返回到之前的状态。我向模型添加了 previous_state 字段,但我看不到如何在事件块内访问它。
这是我试图实现的基本逻辑:
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 文档并不是很有帮助,而且我在网上找不到示例。有时很难知道如何向谷歌描述某些东西:)
I'm trying to implement a "suspend" event that transitions the object to the :suspended state. But I need to be able to "unsuspend", and return to the previous state. I added a previous_state field to the model, but I can't see how to access it inside an event block.
This is the basic logic I'm trying to implement:
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
The state_machine docs haven't been very helpful, and I can't find examples online. Sometimes it's tough to know how to describe something to google :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
state_machine 的作者还在这里提供了替代解决方案:https://groups .google.com/d/msg/pluginaweek-talk/LL9VJdL_x9c/vP1qv6br734J
也就是说:
另一个可能的解决方案是对状态机的工作方式进行一些创意。 ActiveRecord 等 ORM 中有很多钩子,使我们能够在流程的任何阶段设置状态。请考虑以下情况:
在此示例中,引入了一个新状态(已恢复),即使它从未真正保留在数据库中。相反,我们提供了一个 before_validation 钩子,它根据先前的状态重写状态。您可以看到下面的结果:
这应该需要减少一次数据库命中,因为它发生在验证之前。就我而言,完整的图片如下所示:
The author of state_machine has also provided an alternate solution here: https://groups.google.com/d/msg/pluginaweek-talk/LL9VJdL_x9c/vP1qv6br734J
To wit:
Another possible solution is to be a little creative with how the state machine works. There are plenty of hooks in ORMs like ActiveRecord that give us the ability to set the state at any stage in the process. Consider the following:
In this example, a new state, restored, is introduced even though it never actually gets persisted in the database. We instead provide a before_validation hook that rewrites the state based on the previous state. You can see the results below:
This should require one less database hit as it occurs before validation. In my case the complete picture looks like this:
在我看来,这不是一个完美的解决方案,但我确实弄清楚了如何完成我的任务:
我首先向我的机器添加“未挂起”状态。虽然我从不想让某些东西保持在这种状态,但我无法动态地告诉 state_machine 我想要取消挂起到什么状态。
我向挂起事件添加了 before_transition 回调,以保存挂起之前的状态。
我向取消挂起事件添加了 after_transition 回调,因此状态会立即更新到之前的状态,然后擦除之前的状态以防止在对象生命周期的后期出现问题。
这并不完美。它可以工作,但它比仅仅将挂起和取消挂起事件创建为独立方法要复杂得多。我没有走这条路,因为我希望 state_machine 控制所有状态更改,并且突破该路线会消除防止移至/移出无效状态、回调等的保护。
This isn't a perfect solution in my opinion, but I did figure out how to accomplish my task:
I started by adding an "unsuspended" state to my machine. While I never want something to stay in this state, I can't dynamically tell state_machine what state I want to unsuspend to.
I added a before_transition callback to the suspend event, to save the state before it is suspended.
I added an after_transition callback to the unsuspend event, so the state is immediately updated to the previous state, and that previous state is then wiped out to prevent issues later in the object's life.
This is not perfect. It works, but it's a lot more complicated than just creating the suspend and unsuspend events as standalone methods. I didn't go that route because I want state_machine controlling all state changes, and breaking out of that removes the protections against moving to/from invalid states, callbacks, etc.
简单的解决方案
我提供了使用
owner
块参数的解决方案的替代版本。在某些情况下可能有用。around_transition 的使用
另请注意,您可以用
around_transition
替换两个unsuspend
块:Simple solution
I am providing an alternative version to the solution that uses
owner
block argument. Might be useful is some cases.Use of around_transition
Also note that you can replace the two
unsuspend
blocks witharound_transition
: