你推荐哪个状态机插件适用于Rails?

5
我正在寻找一个相对简单的状态机插件,用于Rails 3 / Active Record项目。
我已经做了一些研究,找到了以下插件:
- Transitions: https://github.com/qoobaa/transitions - 从旧的Active Record状态机库中提取 - Acts_As_State_Machine: https://github.com/aasm/aasm - Workflow: https://github.com/geekq/workflow - State Machine: https://github.com/pluginaweek/state_machine - State Flow: https://github.com/ryanza/stateflow

但它们似乎都非常相似,所以我很想知道是否有人在实际应用中有过经验。

谢谢!


注释:我们制作了一个简短的视频(http://www.platform45.com/videos/show/10),解释了状态流,可能会有所帮助。 - Neil
如果想了解它们的相对流行程度,可以在这里查看:https://www.ruby-toolbox.com/categories/state_machines - Nathan Long
6个回答

12

state_machine 似乎是人们常用的选择,至少我跟谈论过的人这样说。它不受环境限制,因此您可以在应用程序的一个部分中使用一个状态机,在该应用程序的另一个部分中完全使用另一个状态机。

更新于2015年2月

不幸的是,State Machine 已不再得到维护,存在着许多问题,这使其成为不太理想的选择。但是,这个项目的分支仍在积极维护,并且似乎很稳定。


4
我最终使用了Stateflow并喜欢它。它可以在Rails 3.0上运行,并且与几个Rails 3.0 beta版本中的状态机代码类似,但被从最终版本中删除。我没有关注目前在Rails中内置状态机的想法是什么,但我猜想如果将来重新集成状态机,它会有点像这样。希望这意味着如果我想放弃gem并使用核心功能,则代码更改将最小化。 https://github.com/ryanza/stateflow

我之前没听说过这个,但我真的很喜欢它的语法。我刚把它加到了上面的列表里。 - Adam Albrecht
Stateflow具有动态转换的优点(您可以使用一些业务逻辑确定下一个状态),如果这是您需要的内容。 - crishoj

3
我会小心地对待转换。作者/提取器说他没有时间维护它,并且通常在他的新项目中偏爱state_machine
另一方面,它确实可用(尽管要检查打开的问题以查看它是否适合您的情况)。我自己正在一个项目中使用转换,但只是用于简单的状态机。
我以前在Rails 2项目中使用过acts作为状态机,它表现得非常好(即使有非常复杂的状态机)。

2
SimpleStateMachine是一种简单的DSL,可用于使用状态转换保护装饰现有方法,点击此处查看更多详情。
class LampSwitch
   extend SimpleStateMachine

   def initialize
     self.state = 'off'
   end

   event :push_switch, :off => :on
end

lamp = LampSwitch.new
lamp.state          # => 'off'
lamp.off?           # => true
lamp.push_switch    #
lamp.state          # => 'on'
lamp.on?            # => true

它与ActiveModel验证一起使用,并允许使用参数调用事件:
class User < ActiveRecord::Base
  ...
  def activate_account(activation_code)
    if activation_code_invalid?(activation_code)
      errors.add(:activation_code, 'Invalid')
    end
  end
  event :activate_account, :invited => :activated
end

user = User.new
user.activate_account!('INVALID') # => raises ActiveRecord::RecordInvalid
user.activated?                     # => false
user.activate_account!('VALID')
user.activated?                     # => true

它可以捕获异常:

def download_data
  raise Service::ConnectionError
end
event :download_data, Service::ConnectionError => :download_failed

user.download_data               # catches Service::ConnectionError
user.state                       # => "download_failed"
user.state_machine.raised_error  # the raised error

0

我建议使用Workflow,因为我认为它是所有可用状态机中最容易使用的。


0

即使是最简单的状态机宝石也比我需要的功能多得多,所以我决定自己开发解决方案。我尝试了Transitions和Stateflow,但两者都有一些小问题。


知道你选择了什么有点有趣,但我不确定这是否算作答案。为什么不把它作为问题的更新呢? - iconoclast
好的,我会将其作为一个答案留下来,但是取消“最佳答案”的标记,因为这实际上是一个开放性问题。 - Adam Albrecht
作为一份真正的答案,难道你不认为你应该分享你使用的代码吗?否则这个问答就变成了“我应该如何做X?”“我自己用的方法是X”。 - iconoclast

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接