Skip to content

Commit 30b4376

Browse files
committed
Add FormStateMachine:event_path
Algorithmically determine the shortest event paths to change the state of a form to another state.
1 parent 1137a1f commit 30b4376

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

app/state_machines/form_state_machine.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,42 @@
11
module FormStateMachine
22
extend ActiveSupport::Concern
33

4+
# delete_form destroys the form rather than just changing its state, and the
5+
# language-specific live events publish only one translation, so a path
6+
# between states must never fire them
7+
EXCLUDED_EVENTS = %i[delete_form make_english_version_live make_welsh_version_live].freeze
8+
9+
class_methods do
10+
# Breadth-first search of the state machine for the shortest sequence of
11+
# events that takes a form from one state to another, so that all event
12+
# callbacks run along the way. Returns an array of event names to fire in
13+
# order, an empty array if the form is already in the target state, or nil
14+
# if no sequence of events reaches it. Event guards such as
15+
# all_ready_for_live? are not evaluated here; they are only checked when
16+
# the events are fired.
17+
def event_path(from:, to:)
18+
event_paths = { from => [] }
19+
queue = [from]
20+
21+
while (state = queue.shift)
22+
return event_paths[state] if state == to
23+
24+
aasm.events.each do |event|
25+
next if EXCLUDED_EVENTS.include?(event.name)
26+
27+
event.transitions_from_state(state).each do |transition|
28+
next if event_paths.key?(transition.to)
29+
30+
event_paths[transition.to] = event_paths[state] + [event.name]
31+
queue << transition.to
32+
end
33+
end
34+
end
35+
36+
nil
37+
end
38+
end
39+
440
included do
541
include AASM
642

0 commit comments

Comments
 (0)