Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AASM: Separating the state machine definition from the class definition

Tags:

module

ruby

aasm

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
like image 399
Gnagno Avatar asked Aug 27 '14 15:08

Gnagno


1 Answers

Couldn't you simple do this?

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

    aasm do
      ...
    end
  end
end
like image 111
alto Avatar answered Nov 14 '22 21:11

alto