How to customize existing state machines
Sometimes you might need to tweak Solidus' core model to fit your business needs. In that case, you might want to tweak a state machine to obey your extended domain.
Say that you must store the time when a payment has been marked as completed.
First, you need to add a new #completed_at
field to the payments table:
bin/rails g migration AddCompletedAtToSpreePayments completed_at:time
bin/rails db:migrate
Next, you can leverage the payment state machine to fill it. You can add an
after_transition hook
using an override (don't forget the setup code in config/application.rb
):
# frozen_string_literal: true
module MyStore
module PaymentSetCompletedAt
def self.prepended(base)
base.state_machine.after_transition(to: :completed) do
self.completed_at = Time.zone.now
end
end
::Spree::Payment.prepend self
end
end
That's all you need to do. From this moment, the state machine will be responsible for storing when a payment is completed.
Be aware of not overusing transition hooks in the state machines. When the involved logic requires
reaching external services or, more generally, is decoupled from the main flow, you're better
off leveraging the event bus. Otherwise, you
will eventually run into the typical gotchas and downsides of abusing
ActiveRecord
callbacks.