DEV: Unify params access in services

Currently, there are two ways (kind of) for accessing `params` inside a
service:
- when there is no contract or it hasn’t been reached yet, `params` is
  just the hash that was provided to the service. To access a key, you
  have to use the bracket notation `params[:my_key]`.
- when there is a contract and it has been executed successfully,
  `params` now references the contract and the attributes are accessible
  using methods (`params.my_key`).

This patch unifies how `params` exposes its attributes. Now, even if
there is no contract at all in a service, `params` will expose its
attributes through methods, that way things are more consistent.

This patch also makes sure there is always a `params` object available
even when no `params` key is provided to the service (this allows a
contract to fail because its attributes are blank instead of having the
service raising an error because it doesn’t find `params` in its context).
This commit is contained in:
Loïc Guitaut
2024-12-11 17:58:17 +01:00
committed by Loïc Guitaut
parent cbc0ece6e8
commit 9e9abe0a82
4 changed files with 57 additions and 3 deletions

View File

@ -441,8 +441,12 @@ module Service
def initialize(initial_context = {})
@context =
Context.build(
initial_context.merge(__steps__: self.class.steps, __service_class__: self.class),
initial_context
.compact
.reverse_merge(params: {})
.merge(__steps__: self.class.steps, __service_class__: self.class),
)
initialize_params
end
# @!visibility private
@ -463,5 +467,21 @@ module Service
context["result.step.#{step_name}"].fail(error: message)
context.fail!
end
private
def initialize_params
klass =
Data.define(*context[:params].keys) do
alias to_hash to_h
delegate :slice, :merge, to: :to_h
def method_missing(*)
nil
end
end
context[:params] = klass.new(*context[:params].values)
end
end
end