Class: Serviced::Service

Inherits:
Object
  • Object
show all
Includes:
ResultHelpers, Typed
Defined in:
lib/serviced/service.rb

Overview

Base class for service objects.

A service declares its inputs as typed attributes (see Typed), which are coerced on assignment and read-only afterwards. Inputs can be validated with the full ActiveModel validation DSL. Calling a service always returns a Result.

class CreatePatient < Serviced::Service
attribute :name,   :string
attribute :age,    :integer
attribute :active, :boolean, default: true
attribute :clinic # untyped: accepts any object

validates :name, presence: true
validates :age, numericality: { greater_than: 0 }

def call
  patient = Patient.create!(name:, age:, active:)
  success(patient)
rescue ActiveRecord::RecordInvalid => e
  failure(:not_created, e.message, error: e)
end
end

result = CreatePatient.call(name: "Ada", age: 36)
result.success? # => true
result.value    # => #<Patient ...>

Invalid inputs short-circuit to failure(:invalid) without running #call, exposing the ActiveModel::Errors object through result.error.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Typed

#initialize

Class Method Details

.call(attributes = {}) ⇒ Serviced::Result

Builds the service, validates it, and runs #call.

Unknown keys are ignored so a service can be dropped into a Flow without matching the exact shape of the flow context.

Parameters:

  • attributes (Hash) (defaults to: {})

    input values

Returns:

Raises:



47
48
49
50
51
52
53
54
55
56
57
# File 'lib/serviced/service.rb', line 47

def call(attributes = {})
  service = new(attributes)
  return service.__send__(:invalid_result) if service.invalid?

  result = service.call
  unless result.is_a?(Result)
    raise ResultTypeError, "#{self}#call must return a Serviced::Result, got #{result.class}"
  end

  result
end

Instance Method Details

#callServiced::Result

The business logic. Subclasses must implement it and return a Result (use the success / failure helpers).

Returns:

Raises:

  • (NotImplementedError)


63
64
65
# File 'lib/serviced/service.rb', line 63

def call
  raise NotImplementedError, "#{self.class} must implement #call"
end