ステータス管理用のgem aasm
を使ってみました。
ちょっとハマったので自分の覚書として残します。
環境:
Ruby2.5.1
Rails5.2.1
背景:
Taskモデルに、ステータス管理機能を追加したい
aasmのリファレンスはこちら
https://github.com/aasm/aasm/blob/master/README.md
リファレンスに沿って実装を進めます。
# Gemfile
gem 'aasm'
Gemfileに追加してbundle install。
ハマったのはこのあと。
リファレンスにはこのように書いてあります。
After installing AASM you can run generator:
% rails generate aasm NAME [COLUMN_NAME]
Replace NAME with the Model name, COLUMN_NAME is optional(default is 'aasm_state'). This will create a model (if one does not exist) and configure it with aasm block. For Active record orm a migration file is added to add aasm state column to table.
結論からいうと、私の場合はTaskモデルがすでに存在し、それに対してステータス管理を追加したいので
$ rails g aasm Task
とすればよかったのですが、最初は意味がわからずに
$ rails g aasm State
という新規のモデル名をつけて実行してしまい、マイグレーション実行時に以下のようなエラーになりました。
NameError: uninitialized constant CreateAasmStates
それはさておき、正しいコマンドを実行すると、以下のようなマイグレーションファイルが完成。
class AddAasmStateToTasks < ActiveRecord::Migration[5.2]
def change
add_column :tasks, :aasm_state, :string
end
end
aasm_stateというのはデフォルトのカラム名。カラム名をstateという名前にしたかったら
$ rails g aasm Task state
とすればよい。
マイグレーションを実行すると、models/task.rbファイルに
include AASM
aasm do
end
というコードが自動的に追加されましたので、以下のように編集。
aasm do
state :waiting, :initial => true
state :wip, :done
event :run do
transitions :from => :waiting, :to => :wip
end
event :finish do
transitions :from => :wip, :to => :done
end
end
簡単に書くと、ステータスにはwaiting、wip、doneの3つがあって、waitingが初期値。
runというイベントが実行されると、waitingからwipに移行し、
finishというイベントが実行されると、wipからdoneに移行するという流れ。
ここでコンソールで確認してみましょう。
$ rails c
でコンソールを起動しといて
irb(main):001:0> task = Task.new(title: "タスク名", content: "タスク内容")
=> #<Task id: nil, title: "タスク名", content: "タスク内容", created_at: nil, updated_at: nil, end_of_task: nil, aasm_state: "waiting">
irb(main):002:0> task.waiting?
=> true
irb(main):003:0> task.wip?
=> false
irb(main):004:0> task.done?
=> false
irb(main):005:0> task.wip?
=> false
irb(main):006:0> task.done?
=> false
irb(main):007:0> task.run
=> true
irb(main):008:0> task.waiting?
=> false
irb(main):009:0> task.wip?
=> true
irb(main):010:0> task.finish
=> true
irb(main):011:0> task.done?
=> true
ここから先についてはまた投稿します。