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:
parent
cbc0ece6e8
commit
9e9abe0a82
|
@ -441,8 +441,12 @@ module Service
|
||||||
def initialize(initial_context = {})
|
def initialize(initial_context = {})
|
||||||
@context =
|
@context =
|
||||||
Context.build(
|
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
|
end
|
||||||
|
|
||||||
# @!visibility private
|
# @!visibility private
|
||||||
|
@ -463,5 +467,21 @@ module Service
|
||||||
context["result.step.#{step_name}"].fail(error: message)
|
context["result.step.#{step_name}"].fail(error: message)
|
||||||
context.fail!
|
context.fail!
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -92,7 +92,7 @@ module Chat
|
||||||
private
|
private
|
||||||
|
|
||||||
def accept_blocks(guardian:, params:)
|
def accept_blocks(guardian:, params:)
|
||||||
params[:blocks] ? guardian.user.bot? : true
|
params.blocks ? guardian.user.bot? : true
|
||||||
end
|
end
|
||||||
|
|
||||||
def no_silenced_user(guardian:)
|
def no_silenced_user(guardian:)
|
||||||
|
|
|
@ -61,7 +61,7 @@ module Chat
|
||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
Chat::Channel.find_by(id: params[:channel_id])
|
Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_channel_permission(guardian:, channel:)
|
def check_channel_permission(guardian:, channel:)
|
||||||
|
|
|
@ -58,4 +58,38 @@ RSpec.describe Service do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "Parameters handling" do
|
||||||
|
subject(:result) { service_class.call(**args) }
|
||||||
|
|
||||||
|
context "when calling the service without any params" do
|
||||||
|
let(:args) { {} }
|
||||||
|
|
||||||
|
it "instantiate a default params object" do
|
||||||
|
expect(result[:params]).not_to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when calling the service with params" do
|
||||||
|
let(:args) { { params: { param1: "one" } } }
|
||||||
|
|
||||||
|
context "when there is no `params` step defined" do
|
||||||
|
it "allows accessing `params` through methods" do
|
||||||
|
expect(result[:params].param1).to eq("one")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nothing for a non-existent key" do
|
||||||
|
expect(result[:params].non_existent_key).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when there is a `params` step defined" do
|
||||||
|
before { service_class.class_eval { params { attribute :param1 } } }
|
||||||
|
|
||||||
|
it "returns the contract as the params object" do
|
||||||
|
expect(result[:params]).to be_a(Service::ContractBase)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue