| name | business-logic-coder |
| description | Implement business logic with ActiveInteraction and AASM state machines. Routes to specialized skills for typed operations and state management. |
Business Logic Patterns
Orchestrator for structured business logic in Rails.
Skill Routing
| Need | Skill | Use When |
|---|
| Typed operations | active-interaction-coder | Creating business operations, refactoring service objects |
| State machines | aasm-coder | Implementing workflows, managing state transitions |
When to Use Each
ActiveInteraction
Use for operations - things that happen once:
- User registration
- Order placement
- Payment processing
- Data imports
- Report generation
outcome = Users::Create.run(email: email, name: name)
AASM
Use for state management - things with lifecycle:
- Order status (pending → paid → shipped)
- Subscription state (trial → active → cancelled)
- Document workflow (draft → review → published)
- Task status (todo → in_progress → done)
order.pay!
order.ship!
Combined Pattern
Often used together - interactions trigger state changes:
module Orders
class Process < ActiveInteraction::Base
object :order, class: Order
def execute
order.process!
fulfill_order(order)
order
end
end
end
Setup
gem "active_interaction", "~> 5.3"
gem "aasm", "~> 5.5"
Quick Reference
ActiveInteraction:
.run - Returns outcome (check .valid?)
.run! - Raises on failure
compose - Call nested interactions
AASM:
.event! - Transition or raise
.event - Transition or return false
.may_event? - Check if transition valid
.aasm.events - List available events
Transaction Boundaries
When business logic involves multi-step database operations, enforce proper transaction boundaries.
Atomic Operations
def transfer_funds(from, to, amount)
from.update!(balance: from.balance - amount)
to.update!(balance: to.balance + amount)
end
def transfer_funds(from, to, amount)
ActiveRecord::Base.transaction do
from.lock!
to.lock!
from.update!(balance: from.balance - amount)
to.update!(balance: to.balance + amount)
end
end
Isolation Levels
ActiveRecord::Base.transaction(isolation: :repeatable_read) do
end
ActiveRecord::Base.transaction(isolation: :serializable) do
end
Deadlock Prevention
Rules:
- Lock records in consistent order (by ID ascending)
- Keep transactions short
- No user input inside transactions
- No external API calls inside transactions
def swap_owners(item_a, item_b)
transaction do
item_a.lock!
item_b.lock!
end
end
def swap_owners(item_a, item_b)
items = [item_a, item_b].sort_by(&:id)
transaction do
items.each(&:lock!)
end
end
Transaction Anti-Patterns
| Anti-Pattern | Problem | Solution |
|---|
| Long transactions | Lock contention | Split into smaller units |
| API calls inside | Timeout blocks DB | Call outside, then transact |
| User input inside | Indefinite locks | Validate first, transact last |
| Nested transactions | Savepoint confusion | Use requires_new: true explicitly |
Nested Transactions
transaction do
create_order!
transaction do
charge_card!
end
end
transaction do
create_order!
transaction(requires_new: true) do
charge_card!
end
end
Related Skills
event-sourcing-coder - Record domain events from state transitions