これ https://github.com/gocardless/statesman
数多の state machine gem の一つ。
- ライブラリが小さいので読みやすい。扱いやすい
- 状態管理をモデルとは切り離した一つのクラスで管理できる
- 定義を DSL 風に書けて読みやすい
- 状態遷移の履歴なんかも自動でとってくれる
- デフォルトではオンメモリでステート管理をし、指定すると永続化も可能
モデル上、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 になっているため、#save!
の呼出しをしたりするとエラーとなります。保存をしたいときは、object.id
で find をかけてあらためてオブジェクトを取り出してやる必要があります。
fixtures の作り方にもよりますが、モデルのために fixtures をロードしても AR の callback を経由しない (DB への insert) ため initial state の設定などが走りません。ここも自分でケアしてやる必要があります (明示的に setup で after_create を走らせるなど)。
gocardless/statesman#19 認識されていて PR 出てるけど、issue 立てた人がレスしないので取り込まれない案件になってる。とりあえず fork して最先端へ修正適用するやつをメンテしてます。
gem 'statesman', git: 'https://github.com/sunaot/statesman.git', branch: 'latest-mysql-fix'
現時点では master にて解消されたものがリリースされており、上記の fork は不要になってます。