Skip to content

Instantly share code, notes, and snippets.

@sunaot
Last active March 8, 2016 07:17
Show Gist options
  • Save sunaot/206b6c3b57045c462d5e to your computer and use it in GitHub Desktop.
Save sunaot/206b6c3b57045c462d5e to your computer and use it in GitHub Desktop.

statesman を解説するよ

statesman is 何?

これ https://github.com/gocardless/statesman

数多の state machine gem の一つ。

特徴

  • ライブラリが小さいので読みやすい。扱いやすい
  • 状態管理をモデルとは切り離した一つのクラスで管理できる
  • 定義を DSL 風に書けて読みやすい
  • 状態遷移の履歴なんかも自動でとってくれる
  • デフォルトではオンメモリでステート管理をし、指定すると永続化も可能

気をつけること

Transition の initial state がセットされない

モデル上、Transition の初期値は initial: true を指定したものが自動的にセットされた状態とみなされます。Statesman はそのように振る舞うのですが、状態の永続化をした場合、永続化層がついてきません。ここは自分でセットしてやる必要があります。AR の場合は、after_create で明示的にセットしてやるのが事故が少なくよさそうです。

after_create :create_transition!

def create_transition!
  self.class.transition_class.create!(to_state: state_machine.class.initial_state, sort_key: 0, metadata: {}, model_name_id: id)
end

before/after_transition 中の object は AR::ReadOnlyRecord

before/after_transition にはモデルクラスのインスタンスである object が引数として渡されます。ただ、このオブジェクトは AR::ReadOnlyRecord になっているため、#save! の呼出しをしたりするとエラーとなります。保存をしたいときは、object.id で find をかけてあらためてオブジェクトを取り出してやる必要があります。

テストのときに fixtures をロードしても状態は追いつかない

fixtures の作り方にもよりますが、モデルのために fixtures をロードしても AR の callback を経由しない (DB への insert) ため initial state の設定などが走りません。ここも自分でケアしてやる必要があります (明示的に setup で after_create を走らせるなど)。

mysql だと動かない

gocardless/statesman#19 認識されていて PR 出てるけど、issue 立てた人がレスしないので取り込まれない案件になってる。とりあえず fork して最先端へ修正適用するやつをメンテしてます。

gem 'statesman', git: 'https://github.com/sunaot/statesman.git', branch: 'latest-mysql-fix'

@sunaot
Copy link
Author

sunaot commented Nov 5, 2014

mysql だと動かない

現時点では master にて解消されたものがリリースされており、上記の fork は不要になってます。

@tmitz
Copy link

tmitz commented Nov 5, 2014

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment