Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically pick state machine? #98

Open
pendletons opened this issue Aug 29, 2023 · 1 comment
Open

Dynamically pick state machine? #98

pendletons opened this issue Aug 29, 2023 · 1 comment

Comments

@pendletons
Copy link

Hello,

We have a multi-tenant application and would like to hard-code our state machine definitions, but be able to dynamically pick which state machine gets selected based on our tenant. I think the dynamic definition in the docs is overkill (and focuses primarily on dynamic transitions while we want the entire thing to be dynamic). Is there a nice way to say, for this class, use this state machine under condition A and use that state machine under condition B?

Ideally, we would like something along the lines of:

class Vehicle
  def initialize
    super
    state_machine = if tenant_a?
                      StateMachineA
                    else
                      StateMachineB
                    end
  end
end

module StateMachineA
  state_machine :state, initial: :parked do
    event :start_car do
      # put in gear
    end
  end
end

module StateMachineB
  state_machine :state, initial: :working do
    event :repair_car do
      # mark as broken
      # fix car
    end

    event :start_car do
      # mark as working
    end
  end
end

So that we can change the behaviour of vehicle.start_car based on which definition file we're using.

Is something like this possible?

@princetechs
Copy link

princetechs commented Nov 5, 2023

you can make multiple instance of your state machine or as per you,

It seems like you want to conditionally select a state machine definition for a class based on a tenant-specific condition. While the Ruby StateMachine gem doesn't provide built-in support for this specific use case, you can achieve your goal by using dynamic class methods to define state machines. Here's one way to do it:

class Vehicle
  def initialize
    super
    state_machine = if tenant_a?
                      StateMachineA.new(self)
                    else
                      StateMachineB.new(self)
                    end
  end
end

class StateMachineBase
  def initialize(vehicle)
    @vehicle = vehicle
  end
end

class StateMachineA < StateMachineBase
  def self.define
    state_machine :state, initial: :parked do
      event :start_car do
        # put in gear
      end
    end
  end
end

class StateMachineB < StateMachineBase
  def self.define
    state_machine :state, initial: :working do
      event :repair_car do
        # mark as broken
        # fix car
      end

      event :start_car do
        # mark as working
      end
    end
  end
end

In this approach:

  1. The Vehicle class initializes an instance of a state machine based on the tenant condition. Each state machine instance is associated with the specific vehicle.

  2. The StateMachineBase class is introduced to provide a common interface for state machines. It takes the vehicle as a parameter during initialization.

  3. StateMachineA and StateMachineB classes define their state machines as class methods (i.e., define). This allows you to conditionally select the state machine based on the tenant and associate it with the vehicle instance.

This way, you can dynamically select and use a state machine based on your tenant conditions without relying on a single, static definition for all instances of Vehicle. let me know if it works for you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants