Ruby on Railsで状態を扱うAASM gem
github.com 上記のAASMというgemを使用して状態遷移を扱う方法を紹介します。
gem導入
Gemfileに下記の通り記述し、
gem 'aasm'
bundlerでインストールしましょう。
bundle install
使い方
例
下記のようなSNSのUserモデルを例に実装します。
リポジトリはこちらです。 github.com
クラス図
状態遷移図
クラス図や状態遷移図はPlantUMLで作成しています。 ngmt83.hatenablog.com
Userモデルにaasm_state
カラムを追加
状態を表すカラムがない場合は下記のrailsコマンドで作成できます。
rails generate aasm user
実際のdiffはこちらです。
CMD: rails generate aasm user · nagamoto/state-machine-sample@2f28fe4 · GitHub
初期状態とすべて状態の定義
state
に状態を列挙し、初期状態をinitial
で指定します。
state :registered, :initial => true state :active, :suspended, :banned, :inactive
状態遷移の定義
状態遷移を伴う操作をevent
とし、transitions
で状態遷移を記述します。
event :ban do transitions from: [:active, :suspended], to: :banned, guard: :build_ban after do create_ban! end end
active
かsuspend
状態のもののみ、ban
という操作でbanned
状態に遷移できます。指定と異なる状態で操作を実行しようとするとAASM::InvalidTransition
という例外が発生します。
また、after
などを用いて状態遷移の前後に操作を記述することもできますし、guard
で状態遷移のためのより詳細な条件をチェックすることができるため、誤った状態遷移を起こさないようにすることもできます。 *1
動的に生成されるメソッド
モデルがxx状態であるか確認するxx?
メソッドやevent
が実行可能かを確認するmay_xx
メソッドなどが使えるようになります。
# userはUser aasm_state=activeのインスタンス user.active? # => true user.banned? # => false user.may_ban? # => true user.ban user.active? # => false user.banned? # => true user.may_ban? # => false user.ban # => raises AASM::InvalidTransition
使い心地
状態遷移時の条件や操作がevent
単位でまとめて記述されるため、見通しが良くなった実感があります。また、必要なメソッドが動的に定義され、コード量が少し減るのもありがたいです。
最後に
このように別の状態管理gemを教えていただいたので、こちらも試してブログに書きたいと思います。*2Railsでステータス管理したいなら https://t.co/uP5W7eFsU4 がシンプルで、コードも読める量でおすすめです #omotesandorb
— 神速 (@sinsoku_listy) 2019年2月7日
※勧められたStatefulEnumについて記事書きました! ngmt83.hatenablog.com