state_machine - 有限狀態機的另一種選擇
在 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
感謝分享!
實用!感謝鴨七!
感恩~ 教學~~
推。。最近的project剛好也用這套,好用!
以前就很想問什麼是 DSL,可以大概解釋一下嗎?因為我怎麼 google 找到的都是另外一個東西。
在這個領域裡面用的語言...