【Rails】AASMを使用してオブジェクトの状態遷移を効率的に管理

はじめに

Railsアプリケーションにおいて、オブジェクトの状態管理は重要な課題の一つです。AASM (Acts As State Machine) gemは、複雑な状態遷移を効率的に管理します。本記事では、AASMの基本的な使い方を解説していきます。

使用方法

セットアップ

まず、Gemfileに以下の行を追加し、bundle installを実行します。

Gemfile

gem 'aasm'

基本的な使用方法

AASMを使用するには、モデルにinclude AASMを追加し、状態とイベントを定義します。以下はOrderモデルの例です。

app/models/order.rb

class Order < ApplicationRecord
  include AASM

  aasm column: 'state' do
    state :pending, initial: true
    state :processing, :shipped, :cancelled

    event :process do
      transitions from: :pending, to: :processing
    end

    event :ship do
      transitions from: :processing, to: :shipped
    end

    event :cancel do
      transitions from: [:pending, :processing], to: :cancelled
    end
  end
end
  • stateカラムを使用して状態を保存
  • 初期状態はpending
  • process、ship, cancelイベントを定義

状態の遷移

状態を遷移させるには、定義したイベントメソッドを呼び出します。

order = Order.create  # 初期状態は pending
order.process!        # pending から processing へ
order.ship!           # processing から shipped へ

状態の確認

現在の状態を確認するには、以下のようにします。

order.pending?    # => true/false
order.processing? # => true/false
order.shipped?    # => true/false
order.cancelled?  # => true/false

遷移の条件

遷移に条件を追加することができます。

aasm do
  event :ship do
    transitions from: :processing, to: :shipped, guard: :all_items_in_stock?
  end
end

def all_items_in_stock?
  order_items.all? { |item| item.in_stock? }
end

この例では、all_items_in_stock?メソッドがtrueを返す場合のみshipイベントが実行されます。

コールバック

遷移の前後にコールバックを追加できます。

aasm do
  event :ship do
    before do
      update_inventory
    end
    transitions from: :processing, to: :shipped
    after do
      send_shipping_notification
    end
  end
end

エラーハンドリング

遷移が失敗した場合、AASMは例外を発生させます。

begin
  order.ship!
rescue AASM::InvalidTransition => e
  puts "Cannot ship order: #{e.message}"
end

高度な使用例

より複雑なワークフローの例として、記事の公開プロセスを考えてみます。

app/models/article.rb

class Article < ApplicationRecord
  include AASM

  aasm column: 'status', whiny_transitions: false do
    state :draft, initial: true
    state :submitted, :reviewed, :approved, :published, :archived

    event :submit do
      transitions from: :draft, to: :submitted
    end

    event :review do
      transitions from: :submitted, to: :reviewed
    end

    event :approve do
      transitions from: :reviewed, to: :approved
    end

    event :publish do
      transitions from: :approved, to: :published, guard: :publishable?
    end

    event :archive do
      transitions from: [:published, :approved], to: :archived
    end
  end

  def publishable?
    !title.blank? && !content.blank?
  end
end
  • 記事は複数の状態(下書き、提出済み、レビュー済み、承認済み、公開済み、アーカイブ済み)を持つ
  • whiny_transitions: falseを設定して、無効な遷移時に例外を発生させないようにする
  • publishable?メソッドを使用して、公開前にタイトルと内容が存在することを確認する

まとめ

AASMは、Railsアプリケーションにおける状態管理を大幅に簡素化し、コードの可読性と保守性を向上させる強力なツールです。状態遷移のロジックを明確に定義し、ビジネスルールを適切に実装することで、より堅牢で柔軟なアプリケーションの開発が可能になります。

関連記事

【Rails】Paranoiaを使用した論理削除(ソフトデリート)
# はじめに Paranoiaは、Railsアプリケーションで論理削除(ソフトデリート)を実現するためのGemです。 論理削除は、データベースのレコードを物理的に削除するのではなく、削除フラグを設定することで「削除済み」とみなす方法です。こ [...]
2024年7月20日 21:33
【Rails】activerecord-multi-tenantを使用したマルチテナントアプリケーションの作成
# はじめに マルチテナントアプリケーションでは、複数の顧客(テナント)が同じアプリケーションを利用するため、データの分離が必要です。 activerecord-multi-tenantは、このようなマルチテナント環境をサポートするための便 [...]
2024年7月18日 16:50
【Rails】RubyとRailsにおけるattr_reader, attr_writer, attr_accessorの概念と使用方法
# はじめに RubyとRailsの開発において、`attr_reader`,`attr_writer`,`attr_accessor`は非常に便利なメソッドです。これらは、クラス内でインスタンス変数に対するゲッターおよびセッターメソッドを簡単に [...]
2024年7月17日 18:11
【Rails】RubyとRailsにおけるyieldの概念と使用方法
# はじめに RubyとRailsにおける`yield`は、メソッドやテンプレートの中で動的にコードブロックを実行する能力を提供し、これによってコードの再利用性と拡張性が大幅に向上します。本記事では、RubyとRailsにおける`yield`の概 [...]
2024年7月17日 13:15
【Rails】RSpec + Swagger + rswagでアプリケーションのAPIをテストおよびドキュメント化する方法
# はじめに Railsアプリケーションの開発において、APIのテストとドキュメント化は重要な要素です。 RSpecはテストフレームワークとして広く利用されており、SwaggerはAPIの設計とドキュメント化を支援します。これらを統合するr [...]
2024年7月16日 14:27
【Rails】mailcatcherを使用して開発環境でメール送信をテストする方法
# はじめに mailcatcherは、開発環境でのメール送信をキャプチャするためのツールです。ローカルで送信されたメールをブラウザ上で簡単に確認できるようにします。mailcatcherをRailsアプリケーションで使用する方法について説明しま [...]
2024年7月15日 16:37
【Rails】impressionistを使用してページビューやクリック数を追跡する方法
# はじめに impressionist Gemを使用してRailsアプリケーションでページビューやクリック数を追跡する方法について説明します。 # 実装方法 ## impressionist Gemのインストール まず、impre [...]
2024年7月15日 14:18
【Rails】meta-tagsを使用したメタタグの管理
# はじめに RailsアプリケーションでSEO対策を行うために、meta-tags Gemを使用してメタタグを管理する方法について説明します。 # メタタグの管理 ## meta-tags Gemのインストール まず、meta-t [...]
2024年7月15日 13:47