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

Passing arrays of states as :to values #80

Closed
pacso opened this issue Sep 10, 2014 · 3 comments
Closed

Passing arrays of states as :to values #80

pacso opened this issue Sep 10, 2014 · 3 comments

Comments

@pacso
Copy link
Contributor

pacso commented Sep 10, 2014

When configuring a transition you can either pass a single state as a string or symbol as the :to argument, or alternatively you can configure multiple transitions by passing an array of strings or symbols.

However, it seems that transition is the only method which accepts arrays when configuring a state machine.

Why do none of the others, such as the before_transition, after_transition callbacks or the guards accept an array of states? Is it a conscious design decision or just something you've not implemented through lack of requirement on your part?

For example, I have a payment system which accepts online payments by cards, or postal payments by cheque. It has a simple state machine:

class OrderStateMachine
  include Statesman::Machine

  state :pending, initial: true
  state :card_payment_declined
  state :card_payment_captured
  state :waiting_cheque
  state :cheque_received

  event :transaction_processed do
    transition from: :pending, to: [:card_payment_captured, :card_payment_declined]
    transition from: :card_payment_declined, to: [:card_payment_captured, :card_payment_declined]
  end

  event :wait_for_postal_payment do
    transition from: :pending, to: :waiting_cheque
  end

  event :cheque_received do
    transition from: :waiting_cheque, to: :cheque_received
  end

  guard_transition to: :card_payment_captured do |object, last_transition, metadata|
    metadata[:action] == 'purchase' && metadata[:success]
  end
end

This uses my modified version of statesman as detailed in pull request #78 which allows the state machine to decide which state to transition to when the :transaction_processed event is triggered based on the metadata passed in from my payment service object.

As you can see, the completion state for card payments is :card_payment_captured, whilst the completion state for postal orders is :cheque_received. However, in both of these cases, once that state is reached, the associated order items need to be marked as paid so that they can be processed.

I would like to be able to use the following syntax when configuring this sort of post-transition processing within a state machine:

  after_transition to: [:card_payment_captured, :cheque_received] do |order|
    order.order_items.each { |order_item| order_item.trigger! :payment_received }
  end

With the existing code I would have to write two separate after_transition callbacks with identical contents, which just doesn't feel right. Before you suggest that I move to a state machine with a single :paid end-state, I'd rather keep the two payment types segregated.

What do you think?

@isaacseymour
Copy link
Contributor

I really like this, much more consistent. I've implemented it in #82 (I think), so would be great if you could take a look at that.

@pacso
Copy link
Contributor Author

pacso commented Sep 13, 2014

As I commented on the PR - I'll pull a copy of this branch and test the new syntax against my existing code. Thanks for this!

@jackfranklin
Copy link
Contributor

This is now done now #83 is merged in.

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

3 participants