36b1f565fc83d9b67588123f2171b896

state_machine - 有限狀態機的另一種選擇

2012-02-15 23:38:27 +0800chitsaouGem 節點 中發起
最後由 xdite2012-02-18 18:03:17 +0800回應 , 907次閱讀

在 rails app 裡面,我們有時候會需要記錄一個 model instance 的狀態 (state) ,要嘛土砲一個(用 constant 存在 integer field),要嘛用人家包好的 gem 。

以前比較流行的是 aasm gem http://github.com/rubyist/aasm ,不過這個 gem 有幾個缺點:

1. 不能判斷物件在某個 state 時,能不能接受某個 event ,來 transfer 到另一個 state ;也就是查詢 transition table 。
2. 沒有 named scope
3. 不能列出這個 model 的所有 states

…好啦至少文件上沒有,我也懶得 trace code 。

就在這個時候我發現了 state_machine 這個 gem: http://github.com/pluginaweek/state_machine

這個目前在 ruby-toolbox 是 state machine 分類裡面最夯的一個,而且:

1. 可以判斷物件在某個 state 時,能不能接受某個 event ,來 transfer 到另一個 state ;也就是查詢 transition table 。
2. 有 named scope
3. 可以畫出 state machine 的圖( DOT 檔,用 Graphviz 畫)
4. 可以列出這個 model 的所有 states
5. 支援很多種 ORM
6. 跟 aasm 一樣有 transition callback
7. 可以依 state 定義 method

要跟 ActiveRecord 整合很簡單,你就加一個叫做 state 的 string field 就好了。

它的 DSL 也很容易理解,要從 aasm 轉換過去很容易:

class Article < ActiveRecord::Base
  state_machine :initial => :draft do
    state :ready
    state :published
    state :rejected

    event :accept do
      transition [:draft, :rejected] => :ready
    end

    event :publish do
      transition :ready => :published
    end

    event :reject do
      transition [:ready, :published] => :rejected
    end
  end
end

可以檢查目前的 state

article = Article.new
article.draft? #=> true
article.published? #=> false
article.state?(:rejected) #=> false

article.accept
article.state #=> "ready"

當目前在某個 state 你可以查詢說能不能接受 event:

# continued from the previous block

article.can_accept? #=> false
article.can_publish? #=> true

這樣就可以無痛整合 cancan 了!

另外也可以掛 named scope:

class Article < ActiveRecord::Base
  scope :published, with_state(:published)
  scope :working, without_state(:published)
end

其他範例可以看官方文件,與 ActiveRecord 相關的操作在這裡:

http://rdoc.info/github/pluginaweek/state_machine/StateMachine/Integrations/ActiveRecord

截至 2012-02-18 18:03:17 +0800,共收到 6 條回應
05aa1ad3ce845138f94690958857c677
bindiry 1樓, 於2012-02-16 00:22:23 +0800回應

感謝分享!

C814acfd2c0897d2fc20de6800b76293
hSATAC 2樓, 於2012-02-16 07:53:35 +0800回應

實用!感謝鴨七!

E13e24a4a8332f251c58f30559f3c176
run26kimo 3樓, 於2012-02-16 12:53:01 +0800回應

感恩~ 教學~~

105d5812431a3311974c1e239c269610
warmwater 4樓, 於2012-02-18 13:49:10 +0800回應

推。。最近的project剛好也用這套,好用!

2a01ae9942939ee2b3954a6727d2bb92
tonytonyjan 5樓, 於2012-02-18 16:35:45 +0800回應

以前就很想問什麼是 DSL,可以大概解釋一下嗎?因為我怎麼 google 找到的都是另外一個東西。

19e786a2a74377ff6e052d87fd8d1fa8
xdite 6樓, 於2012-02-18 18:03:16 +0800回應

在這個領域裡面用的語言...

需要 登入 後方可回應,如果你還沒有帳號按這裡 註冊