Implement state machines with AASM for workflow management. Covers state transitions, guards, callbacks, and testing.
View on GitHubmajesticlabs-dev/majestic-marketplace
majestic-rails
January 24, 2026
Select agents to install to:
npx add-skill https://github.com/majesticlabs-dev/majestic-marketplace/blob/main/plugins/majestic-rails/skills/aasm-coder/SKILL.md -a claude-code --skill aasm-coderInstallation paths:
.claude/skills/aasm-coder/# AASM Coder
State machine patterns for managing workflow states in Rails.
## Setup
```ruby
# Gemfile
gem "aasm", "~> 5.5"
```
## Basic State Machine
```ruby
class Order < ApplicationRecord
include AASM
aasm column: :status do
state :pending, initial: true
state :paid
state :processing
state :shipped
state :cancelled
event :pay do
transitions from: :pending, to: :paid
after do
OrderMailer.payment_received(self).deliver_later
end
end
event :process do
transitions from: :paid, to: :processing
end
event :ship do
transitions from: :processing, to: :shipped
end
event :cancel do
transitions from: [:pending, :paid], to: :cancelled
before do
refund_payment if paid?
end
end
end
end
```
## Usage
```ruby
order = Order.create!
order.pending? # => true
order.may_pay? # => true
order.pay! # Transition + callbacks
order.paid? # => true
order.may_ship? # => false (must process first)
order.aasm.events # => [:process, :cancel]
# Scopes created automatically
Order.pending
Order.paid.where(user: current_user)
```
## Guards
```ruby
event :pay do
transitions from: :pending, to: :paid, guard: :payment_valid?
end
def payment_valid?
payment_method.present? && total > 0
end
# Usage
order.pay! # Raises AASM::InvalidTransition if guard fails
order.pay # Returns false (no exception)
```
## Callbacks
```ruby
aasm do
# State callbacks
state :paid, before_enter: :validate_payment,
after_enter: :send_receipt
# Event callbacks
event :ship do
before do
generate_tracking_number
end
after do
notify_customer
end
transitions from: :processing, to: :shipped
end
end
```
**Callback order:**
1. `before` (event)
2. `before_exit` (old state)
3. `before_enter` (new state)
4. State change persisted
5. `after_exit` (old state)
6. `after_enter` (new state)
7. `after` (even