AASM: Separating the state machine definition from the class definition
Asked Answered
C

1

9

suppose I have this class (taken directly from the aasm documentation):

class Job < ActiveRecord::Base
  include AASM

  aasm do
    state :sleeping, :initial => true
    state :running
    state :cleaning

    event :run do
      transitions :from => :sleeping, :to => :running
    end

    event :clean do
      transitions :from => :running, :to => :cleaning
    end

    event :sleep do
      transitions :from => [:running, :cleaning], :to => :sleeping
    end
  end

end

I don't like a lot the fact that I have my state machine definition mixed with my class definition (since of course in a real project I will add more methods to the Job class).

I would like to separate the state machine definition in a module so that the Job class can be something along the line of:

class Job < ActiveRecord::Base
  include StateMachines::JobStateMachine
end

I then created a job_state_machine.rb file in app/models/state_machines with a content similar to:

module StateMachines::JobStateMachine
  include AASM

  aasm do
    state :sleeping, :initial => true
    state :running
    state :cleaning

    event :run do
      transitions :from => :sleeping, :to => :running
    end

    event :clean do
      transitions :from => :running, :to => :cleaning
    end

    event :sleep do
      transitions :from => [:running, :cleaning], :to => :sleeping
    end
  end

end

but this is not working because AASM is being included in the module not in the Job class... I even tried changing the module to:

module StateMachines::JobStateMachine
  def self.included(base)
  include AASM

  aasm do
    state :sleeping, :initial => true
    state :running
    state :cleaning

    event :run do
      transitions :from => :sleeping, :to => :running
    end

    event :clean do
      transitions :from => :running, :to => :cleaning
    end

    event :sleep do
      transitions :from => [:running, :cleaning], :to => :sleeping
    end
  end
  end
end

but still it is not working... any hint or suggestion is very appreciated.

Thanks, Ignazio


EDIT:

Thanks to Alto, the correct solution is this:

module StateMachine::JobStateMachine

  def self.included(base)
    base.send(:include, AASM)

    base.send(:aasm, column: 'status') do
    ....
    end
  end
end

and obviously remember to include the state machine definition in the main class like this:

include StateMachine::JobStateMachine
Cnut answered 27/8, 2014 at 15:7 Comment(0)
G
8

Couldn't you simple do this?

module StateMachines::JobStateMachine
  def self.included(base)
    base.send(:include, AASM)

    aasm do
      ...
    end
  end
end
Gramarye answered 27/8, 2014 at 20:22 Comment(1)
Thank you alto, you put me on the right path, I will modify my question accordingly for whoever will come here in futureCnut

© 2022 - 2024 — McMap. All rights reserved.