Class: TransitionButtons::EventResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/transition_buttons/event_resolver.rb

Overview

Single source of truth shared by the view helper and the controller, so the buttons a user sees and the transitions the endpoint accepts can never drift apart. The view renders permitted_events; the controller re-derives the same set server-side before firing (the buttons are a hint, never the security boundary).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(record:, user:, machine: nil, adapter: nil, authorizer: nil) ⇒ EventResolver

Returns a new instance of EventResolver.



10
11
12
13
14
15
16
# File 'lib/transition_buttons/event_resolver.rb', line 10

def initialize(record:, user:, machine: nil, adapter: nil, authorizer: nil)
  @record = record
  @user = user
  @machine = (machine || TransitionButtons.config.default_machine).to_sym
  @adapter = adapter || TransitionButtons.config.state_machine_adapter
  @authorizer = authorizer || TransitionButtons.config.authorizer
end

Instance Attribute Details

#machineObject (readonly)

Returns the value of attribute machine.



8
9
10
# File 'lib/transition_buttons/event_resolver.rb', line 8

def machine
  @machine
end

Instance Method Details

#current_stateObject



36
37
38
# File 'lib/transition_buttons/event_resolver.rb', line 36

def current_state
  @adapter.current_state(@record, machine: @machine)
end

#domain_event?(event) ⇒ Boolean

Returns:

  • (Boolean)


23
24
25
# File 'lib/transition_buttons/event_resolver.rb', line 23

def domain_event?(event)
  domain_events.include?(event.to_sym)
end

#domain_eventsObject

Events the state machine allows from the current state (guards applied).



19
20
21
# File 'lib/transition_buttons/event_resolver.rb', line 19

def domain_events
  @domain_events ||= Array(@adapter.available_events(@record, machine: @machine)).map(&:to_sym)
end

#fire(event) ⇒ Object

Fires the event. Returns the adapter's truthy/falsey result. Does NOT enforce authorization itself — callers (the controller) must check permitted? first; this keeps the security decision explicit at the boundary rather than buried in a side effect.



44
45
46
# File 'lib/transition_buttons/event_resolver.rb', line 44

def fire(event)
  @adapter.fire(@record, event.to_sym, machine: @machine)
end

#permitted?(event) ⇒ Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/transition_buttons/event_resolver.rb', line 32

def permitted?(event)
  domain_event?(event) && authorized?(event)
end

#permitted_eventsObject

The intersection the UI cares about: legal AND authorized for this user.



28
29
30
# File 'lib/transition_buttons/event_resolver.rb', line 28

def permitted_events
  domain_events.select { |event| authorized?(event) }
end