Class: Plutonium::Interaction::Base

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Attributes, ActiveModel::Model, Definition::ConfigAttr, Definition::DefineableProps, Definition::FormLayout, Definition::InheritableConfigAttr, Definition::PageWidths, Definition::Presentable, Definition::StructuredInputs, Concerns::Dispatchable
Defined in:
lib/plutonium/interaction/base.rb

Overview

Note:

Subclasses must implement the #execute method.

Base class for all interactions.

An interaction is a presentation object: it declares the inputs for an operation, renders as a button and a form, is gated by a policy, and returns an Outcome the controller turns into a flash message and a redirect. It provides validations (of input shape), execution, and result handling.

It cannot be constructed without a view_context: — which is precisely the boundary it marks. Logic may start in #execute; a one-off with a single caller is fine there, and pre-extracting is YAGNI. But the moment a second caller appears — a background job, an API controller, a rake task, the console — move the behaviour onto the model, Rails-style. Otherwise that caller must either duplicate it or manufacture a view_context it has no business owning.

Examples:

The model owns what "confirming" means; the interaction presents it

class ConfirmUserInteraction < Plutonium::Interaction::Base
  attribute :resource
  attribute :confirmed_at, :datetime, default: -> { Time.current }

  validates :confirmed_at, presence: true

  private

  def execute
    resource.confirm!(at: confirmed_at)   # User#confirm! — reachable from a job too
    succeed(resource).with_message("User confirmed.")
  rescue ActiveRecord::RecordInvalid => e
    failed(e.record.errors)
  end
end

See Also:

Direct Known Subclasses

Resource::Interaction

Defined Under Namespace

Classes: Form

Constant Summary

Constants included from Definition::FormLayout

Definition::FormLayout::UNGROUPED_KEY

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Definition::PageWidths

#display_width_classes, #form_width_classes, #resolved_display_width, #resolved_form_width

Methods included from Definition::FormLayout

assign_ownership, #defined_form_layout, #resolve_form_sections, resolve_sections

Methods included from Definition::StructuredInputs

#defined_structured_inputs

Methods included from Definition::Presentable

#description, #icon, #label

Constructor Details

#initialize(view_context:, **attributes) ⇒ Base

Returns a new instance of Base.



88
89
90
91
# File 'lib/plutonium/interaction/base.rb', line 88

def initialize(view_context:, **attributes)
  super(attributes)
  @view_context = view_context
end

Instance Attribute Details

#view_contextObject (readonly)

Returns the value of attribute view_context.



86
87
88
# File 'lib/plutonium/interaction/base.rb', line 86

def view_context
  @view_context
end

Class Method Details

.build_form(instance) ⇒ Object

Raises:

  • (ArgumentError)


76
77
78
79
80
# File 'lib/plutonium/interaction/base.rb', line 76

def build_form(instance)
  raise ArgumentError, "instance is required" unless instance

  self::Form.new(instance)
end

.callObject



72
73
74
# File 'lib/plutonium/interaction/base.rb', line 72

def call(...)
  new(...).call
end

.structured_input(name, **options, &block) ⇒ Object

On interactions, declaring a structured input also declares the backing ActiveModel attribute so the value survives attributes= and appears in attribute_names (which drives the interaction form's field list).



61
62
63
64
65
# File 'lib/plutonium/interaction/base.rb', line 61

def self.structured_input(name, **options, &block)
  super
  default = options[:repeat] ? -> { [] } : -> { {} }
  attribute name, default: default
end

Instance Method Details

#build_formObject



93
94
95
# File 'lib/plutonium/interaction/base.rb', line 93

def build_form
  self.class.build_form(self)
end

#callPlutonium::Interaction::Outcome

Executes the interaction.

Returns:



100
101
102
103
104
105
106
107
108
109
# File 'lib/plutonium/interaction/base.rb', line 100

def call
  return failure unless valid?

  outcome = execute
  unless outcome.is_a?(Plutonium::Interaction::Outcome)
    raise "#{self.class}#execute must return an instance of Plutonium::Interaction::Outcome.\n" \
          "#{outcome.inspect} received instead"
  end
  outcome
end