← Back to Upcase

Extracting AASM


(Lenart Rudel) #1

I’d like to ask for an opinion about state machine (aasm gem). My main domain model was full of event and transition definitions along with callbacks that occur when the state changes and guards that check a transition can occur. Would you recommend extracting this into a module or is there an even better way?

I was thinking of extracting a couple of concerns but I got concerned ( :smile: ) because these concerns wouldn’t actually include shared behaviour but would be specific to each model. It looks like Module is somewhat closer to what I need. I could still extend the module with ActiveSupport::Concern to take advantage of included, ClassMethods etc.

Here’s an example of what I’m talking about

# app/models/order.rb
class Order < ActiveRecord::Base
  include StateMachine
  ...
end


# app/models/order/state_machine.rb
module Order::StateMachine
  extend ActiveSupport::Concern

  included do
    include AASM
    aasm do
      state :incomplete, initial: true
      state :placed
      state :canceled
      state :completed

      event :place do
        transitions from: :incomplete, to: :placed
      end

      event :complete, before: :finalize_order do
        transitions from: :placed, to: :completed, guard: :valid_payment?
      end

      event :cancel do
        transitions from: :placed, to: :canceled
      end
    end
  end

  def finalize_order
    ...
  end

  def valid_payment?
    ...
  end

end

What do you think? How would you tackle such problem?


(Ben Orenstein) #2

Normally I wouldn’t use a module for this.

Pretty much the only thing that modules bring to the table is that they let you share behavior. If you’re just using them to hold related methods, you’re only pushing your peas around the plate–your class is just as complex, it just appears somewhat smaller when you look at it.

I prefer to extract a class to reduce an object’s responsibilities.

That said, I don’t hate the idea of a module in this exact instance, because I don’t think AASM works well unless it’s mixed into the class you want to have a state machine (I might be wrong about this).