Я впервые использую AASM, и мне интересно, как я могу достичь реализации в подсостоянии. Чистый пример, как я учусь через это. Допустим, мы отслеживаем состояние пациента, когда он проходит через больницу. Вот воображаемый список состояний и подсостояний:
state :entered, initial: true
substate :in_lounge
substate :in_smoking_area
substate :in_restroom
state :with_doctor
substate :checked_vitals
substate :received_consultation
state :checkout
substate :payment_pending
substate :payment_success
substate :payment_error
state :complete
2 правила:
- Major
states
обычно продвигаются вперед линейно, но откат иногда возможен - в пределах данного
state
доступны только те, которые связаны substates
, хотя они не являются линейными и могут двигаться вперед и назад
Например, после того, как вы попали в больницу, вы можете подождать где-нибудь, подсостояния похожи на места. Однако, как только вы with_doctor
, вы больше не можете находиться в гостиной, месте для курения или уборной, если только по какой-то причине врач не отправит вас обратно к entered
.
Моему нынешнему воображаемому , непроверенное решение (некоторые синтаксис может быть не идеальным, но идея несет в себе) состоит в том, чтобы использовать 2 конечных автомата:
- Первичный отслеживает основной
state
и не обновляется напрямую, он функционирует исключительно как защита - Вторичное обновление напрямую обновляется, обратные вызовы в дополнительном состоянии используются для обновления основного состояния
Например:
aasm(:primary, column:"primary_state") do
state :primary_entered, initial: true
state :primary_with_doctor
state :primary_checkout
state :primary_complete
event :to_primary_with_doctor do
transitions from: :primary_entered, to: :primary_with_doctor
end
end
aasm(:secondary, column:"secondary_state") do
state :entered, initial: true
state :in_lounge
state :in_smoking_area
state :in_restroom
state :with_doctor
... # this example only works with substates for first state
[:in_smoking_area, :in_lounge, :in_restroom].each do |this_state|
event :"to_#{this_state}" do
transitions to: this_state, guard: :before_primary_with_doctor
end
# by not specifying a from, this captures notion that any movements in any direction between this set of states is allowable, as long as the guard is met
end
event :to_with_doctor do
transitions to: :with_doctor, guard: :before_primary_with_doctor, success: :set_primary_state("with_doctor")
# secondary state machine has a redundant state, that updates the primary state, allowing primary state to only be used as guards and not to be directly manipulated by the system
end
end
def before_primary_with_doctor
return self.aasm(:primary).current == :entered
# eventually I'm thinking about making primary state enums so I can mathematically do something like...
# self.aasm(:primary).current <= :with_doctor
# obviously syntax not right, but that's how I'm thinking of using this
end
def set_primary_state(state)
self.aasm(:primary).fire(:"to_primary_#{state}")
end
Впервые используя этот драгоценный камень, так что интересно, если это супер хакерский или есть другие, более традиционные способы сделать это.