pluginaweek / state_machine

Adds support for creating state machines for attributes on any Ruby class
http://www.pluginaweek.org
MIT License
3.74k stars 505 forks source link

How to specify conditional state changes using dynamic state definitions #356

Closed tonyvince closed 5 years ago

tonyvince commented 6 years ago

I had a previous state machine like the following

state_machine :state, :initial => :awaiting_quote, use_transactions: false do
  event :submit_quote do
    transition :awaiting_quote => :awaiting_quote_acceptance, 
              if: :line_item_details_complete?
  end
  event :accept_quote do
    transition :awaiting_quote_acceptance => :awaiting_final_invoice
  end
  event :decline_quote do
    transition :awaiting_quote_acceptance => :awaiting_quote
  end
  event :submit_final_invoice do
    transition :awaiting_final_invoice => :awaiting_order_acceptance,
              if: :attachment?
  end
  event :accept_order do
    transition :awaiting_order_acceptance => :order_placed
  end
end

as you can see 2 of the state changes are dependent on line_item_details_complete? and attachment?

Now I am trying to implement the same state machine using dynamic state definitions

  # Replace this with an external source (like a db)
  def transitions
    [
      { :awaiting_quote => :awaiting_quote_acceptance, :on => :submit_quote },
      { :awaiting_quote_acceptance => :awaiting_final_invoice, :on => :accept_quote },
      { :awaiting_quote_acceptance => :awaiting_quote, :on => :decline_quote },
      { :awaiting_final_invoice => :awaiting_order_acceptance, :on => :submit_final_invoice },
      { :awaiting_order_acceptance => :order_placed, :on => :accept_order }
      # ...
    ]
  end

  # Create a state machine for this quotation instance dynamically based on the
  # transitions defined from the source above
  def machine
    quotation = self
    @machine ||= Machine.new(quotation, :initial => :awaiting_quote, :action => :save_state) do
      quotation.transitions.each { |attrs| transition(attrs) }
    end
  end

  # Save the state change
  def save_state
    self.save!
  end

Now how do I use the same conditional state changes based on line_item_details_complete? and attachment? in the second approach? Thank you