Class: BetterService::Workflowable::Step
- Inherits:
-
Object
- Object
- BetterService::Workflowable::Step
- Defined in:
- lib/better_service/concerns/workflowable/step.rb
Overview
Step - Represents a single step in a workflow pipeline
Each step wraps a service class and defines how data flows into it, whether it’s optional, conditional execution, and rollback behavior.
Example:
step = Step.new(
name: :create_order,
service_class: Order::CreateService,
input: ->(ctx) { { items: ctx.cart_items } },
optional: false,
condition: ->(ctx) { ctx.cart_items.any? },
rollback: ->(ctx) { ctx.order.destroy! }
)
step.call(context, user, params)
Instance Attribute Summary collapse
-
#condition ⇒ Object
readonly
Returns the value of attribute condition.
-
#input_mapper ⇒ Object
readonly
Returns the value of attribute input_mapper.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#optional ⇒ Object
readonly
Returns the value of attribute optional.
-
#rollback_block ⇒ Object
readonly
Returns the value of attribute rollback_block.
-
#service_class ⇒ Object
readonly
Returns the value of attribute service_class.
Instance Method Summary collapse
-
#call(context, user, base_params = {}) ⇒ Hash
Execute the step.
-
#initialize(name:, service_class:, input: nil, optional: false, condition: nil, rollback: nil) ⇒ Step
constructor
A new instance of Step.
-
#rollback(context) ⇒ Object
Execute rollback for this step.
Constructor Details
#initialize(name:, service_class:, input: nil, optional: false, condition: nil, rollback: nil) ⇒ Step
Returns a new instance of Step.
24 25 26 27 28 29 30 31 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 24 def initialize(name:, service_class:, input: nil, optional: false, condition: nil, rollback: nil) @name = name @service_class = service_class @input_mapper = input @optional = optional @condition = condition @rollback_block = rollback end |
Instance Attribute Details
#condition ⇒ Object (readonly)
Returns the value of attribute condition.
22 23 24 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 22 def condition @condition end |
#input_mapper ⇒ Object (readonly)
Returns the value of attribute input_mapper.
22 23 24 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 22 def input_mapper @input_mapper end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
22 23 24 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 22 def name @name end |
#optional ⇒ Object (readonly)
Returns the value of attribute optional.
22 23 24 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 22 def optional @optional end |
#rollback_block ⇒ Object (readonly)
Returns the value of attribute rollback_block.
22 23 24 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 22 def rollback_block @rollback_block end |
#service_class ⇒ Object (readonly)
Returns the value of attribute service_class.
22 23 24 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 22 def service_class @service_class end |
Instance Method Details
#call(context, user, base_params = {}) ⇒ Hash
Execute the step
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 39 def call(context, user, base_params = {}) # Check if step should be skipped due to condition if should_skip?(context) return { success: true, skipped: true, message: "Step #{name} skipped due to condition" } end # Build input params for the service service_params = build_params(context, base_params) # Call the service - returns [object, metadata] tuple service_result = service_class.new(user, params: service_params).call # Normalize result to hash format (services now return [object, metadata] tuple) result = normalize_service_result(service_result) # Store result in context if successful if result[:success] store_result_in_context(context, result) elsif optional # If step is optional and failed, continue but log the failure context.add(:"#{name}_error", result[:errors] || result[:validation_errors]) return { success: true, optional_failure: true, message: "Optional step #{name} failed but continuing", errors: result[:errors] || result[:validation_errors] } end result rescue StandardError => e # If step is optional, swallow the error and continue if optional context.add(:"#{name}_error", e.) { success: true, optional_failure: true, message: "Optional step #{name} raised error but continuing", error: e. } else raise e end end |
#rollback(context) ⇒ Object
Execute rollback for this step
92 93 94 95 96 97 98 99 100 101 |
# File 'lib/better_service/concerns/workflowable/step.rb', line 92 def rollback(context) return unless rollback_block if rollback_block.is_a?(Proc) context.instance_exec(context, &rollback_block) else rollback_block.call(context) end # Note: Exceptions are propagated to workflow which wraps them in RollbackError end |