Using Enums as a Simple State Machine
Even without a dedicated state machine, you can enforce some logic using enums.
Example: Enforcing Transitions in Methods
class Order < ApplicationRecord
enum :status, { pending: 0, confirmed: 1, shipped: 2, delivered: 3, canceled: 4 }
def confirm!
update!(status: :confirmed) if pending?
end
def ship!
update!(status: :shipped) if confirmed?
end
def deliver!
update!(status: :delivered) if shipped?
end
end
Now, calling order.ship!
directly won’t work unless it’s confirmed first.
order = Order.new
order.ship! # ❌ This won’t work because the order isn’t confirmed.
order.confirm!
order.ship! # ✅ Now it's valid.
While this improves state management, it still doesn’t strictly prevent developers from manually setting invalid states.