https://github.com/pluginaweek/state_machine
今回はstate_machineを使ってUserモデルに状態を管理する機能を追加します。
インストールする
# Gemfile gem 'state_machine'
$ bundle install
使い方
# app/models/user.rb class User < ActiveRecord::Base state_machine :status, initial: :inactive do state :active # 有効 state :inactive # 無効 # 有効になった時にメールを送信する after_transition on: :activate, do: :send_mail # 失敗した場合にメールを送信する after_failure on: :activate, do: :send_mail event :activate do transition :inactive => :active end event :inactivate do transition :active => :inactive end end def send_mail p "メールを送信しました" end end
> user = User.new(name: "hoge") > user.active? # => false > user.inactive? # => true > user.activate! # => "メールを送信しました" > user.status # => "active" > user.inactivate! > user.status # => "inactive"
日本語化する
# config/locales/state_machine_ja.yml ja: activerecord: state_machines: states: nil: "" user: status: states: active: 有効 inactive: 無効
# human_カラム名_name > user = User.new(name: "hoge") > user.human_status_name # => "無効"
セレクトボックスのタグの情報にstate_machineの状態を使う
# app/models/user.rb class User < ActiveRecord::Base ... def self.status_options states = state_machines[:status].states states.map(&:human_name).zip(states.map(&:value)) end end
# app/views/users/index.html.erb <%= f.select :status, User.status_options %>
specを書く
# spec/models/user_spec.rb require 'spec_helper' describe User do let(:user) { FactoryGirl.build(:user) } describe "state_machine" do describe "status" do it "should be an initial state" do expect(user.status).to eq("inactive") end context "status is active" do before { user.status = "active" } context "to inactive" do before { user.inactivate! } it { expect(user.status).to eq("inactive") } end end context "status is inactive" do before { user.status = "inactive" } context "to active" do before { user.activate! } it { expect(user.status).to eq("active") } end end end end end