Movatterモバイル変換


[0]ホーム

URL:


状態遷移をスマートに実装するためのRailsプラグイン aasm

こんにちは。ハートレイルズの前島(@netwillnet)です。今回はaasm という、状態遷移をスマートに管理するためのRailsプラグインの紹介をしようと思います。

インストール方法

gem install aasm

だけ。

どういうときに使えるの?

複数の状態を持つモデルを管理するときに威力を発揮します。例として、所有している本の状態を管理するモデルを書いてみましょう。状態には

  • 未読(not_read)
  • 読んでる途中(reading)
  • 既読(read)
  • 捨てた(dump)

の4つがあるとし、 status カラムで管理します。また、別の状態として「友達に貸している」を管理する lending カラムを定義しているとします。

状態遷移系のメソッドを aasm を使わず、素直に書くと

class Book < ActiveRecord::Base  # status  : 読書の状態を管理するカラム(integer)  # lending : 友達に貸しているか否かを管理するカラム(boolean)  before_create :set_initial_state  STATUS = {:not_read => 0, :reading => 1, :read => 2, :dump => 3}  def reading    # 未読以外の状態/友達に貸している状態からは遷移させない    if !status.nil? && status != STATUS[:not_read] || lending      return    end    self.status = STATUS[:reading]  end  def read    # 未読/読んでる途中以外の状態/友達に貸している状態からは遷移させない    return if !status.nil? && status != STATUS[:not_read] &&  status != STATUS[:reading] || lending    self.status = STATUS[:read]  end  def dump    # 友達に貸している状態からは遷移させない    return if lending    self.status = STATUS[:dump]  end  private  def set_initial_state    self.status = STATUS[:not_read] if status.nil?  endend

こんな感じでしょうか。これくらいなら別に aasm を導入しなくても何とかなりますが、状態遷移させるかどうか判定する条件式が面倒ですね。もし、状態の数や条件がもっと多かったらどうでしょう・・・うんざりしてきますね。

これを aasm を使って書くと下記のようになります。

class Book < ActiveRecord::Base  # status  : 読書の状態を管理するカラム(string)  # lending : 友達に貸しているか否かを管理するカラム(boolean)  include AASM  aasm_column :status  aasm_initial_state :not_read  aasm_state :not_read  aasm_state :reading  aasm_state :read  aasm_state :dump  aasm_event :reading do    transitions :to => :read, :from => :not_read, :guard => :not_lending?  end  aasm_event :read do    transitions :to => :read, :from => [:not_read, :reading], :guard => :not_lending?  end  aasm_event :dump do    transitions :to => :dump, :from => [:not_read, :reading, :read], :guard => :not_lending?  end  def not_lending?    !lending  endend

どうでしょうか。だいぶすっきりしたように思いませんか?

それぞれのメソッドの意味

コードを見れば大体わかると思いますが、簡単に説明します。

aasm_column
aasm で扱うカラムを指定します。
aasm_initial_state
初期状態を symbol で指定します。
aasm_state
状態の候補を設定します。
aasm_event
引数に指定した symbol が、状態を変化させるためのメソッドになります。保存はされません。保存も同時にするには"!"をメソッド名末尾に付ける必要があります。 ブロック中の transition メソッドで 遷移先の状態(:toオプションで指定)と遷移前の状態(:fromオプションで指定)を設定します。:from で設定した以外での状態の時に遷移しようとすると、AASM::InvalidTransition の例外が発生し、遷移しません。また、:guard で指定したメソッドを実行して false が返ってきた場合も状態遷移しません(この場合は例外は発生せず、falseが返ります)。

まとめ

というわけで、 aasm を使うとこのような感じで複雑な状態管理をスマートに書くことが出来ます。みなさんも使ってみてはどうでしょうか。


[8]ページ先頭

©2009-2025 Movatter.jp