mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Allow chat services to have optional models
This is extracted from #22390. This patch adds a new `optional` option to the `model` step. This means if an optional model returns something blank (`nil` or an empty collection) then the service won’t fail and will execute the next step. However if a model is properly returned, the step will try to check if it is valid or not (if it responds to `#invalid?`). If the model isn’t valid, then the step will fail (so no change here).
This commit is contained in:
parent
c90e399003
commit
050828d1de
@ -74,8 +74,8 @@ module Service
|
|||||||
# Internal module to define available steps as DSL
|
# Internal module to define available steps as DSL
|
||||||
# @!visibility private
|
# @!visibility private
|
||||||
module StepsHelpers
|
module StepsHelpers
|
||||||
def model(name = :model, step_name = :"fetch_#{name}")
|
def model(name = :model, step_name = :"fetch_#{name}", optional: false)
|
||||||
steps << ModelStep.new(name, step_name)
|
steps << ModelStep.new(name, step_name, optional: optional)
|
||||||
end
|
end
|
||||||
|
|
||||||
def contract(name = :default, class_name: self::Contract, default_values_from: nil)
|
def contract(name = :default, class_name: self::Contract, default_values_from: nil)
|
||||||
@ -131,9 +131,16 @@ module Service
|
|||||||
|
|
||||||
# @!visibility private
|
# @!visibility private
|
||||||
class ModelStep < Step
|
class ModelStep < Step
|
||||||
|
attr_reader :optional
|
||||||
|
|
||||||
|
def initialize(name, method_name = name, class_name: nil, optional: nil)
|
||||||
|
super(name, method_name, class_name: class_name)
|
||||||
|
@optional = optional.present?
|
||||||
|
end
|
||||||
|
|
||||||
def call(instance, context)
|
def call(instance, context)
|
||||||
context[name] = super
|
context[name] = super
|
||||||
raise ArgumentError, "Model not found" if context[name].blank?
|
raise ArgumentError, "Model not found" if !optional && context[name].blank?
|
||||||
if context[name].try(:invalid?)
|
if context[name].try(:invalid?)
|
||||||
context[result_key].fail(invalid: true)
|
context[result_key].fail(invalid: true)
|
||||||
context.fail!
|
context.fail!
|
||||||
@ -232,9 +239,10 @@ module Service
|
|||||||
end
|
end
|
||||||
|
|
||||||
# @!scope class
|
# @!scope class
|
||||||
# @!method model(name = :model, step_name = :"fetch_#{name}")
|
# @!method model(name = :model, step_name = :"fetch_#{name}", optional: false)
|
||||||
# @param name [Symbol] name of the model
|
# @param name [Symbol] name of the model
|
||||||
# @param step_name [Symbol] name of the method to call for this step
|
# @param step_name [Symbol] name of the method to call for this step
|
||||||
|
# @param optional [Boolean] if +true+, then the step won’t fail if its return value is falsy.
|
||||||
# Evaluates arbitrary code to build or fetch a model (typically from the
|
# Evaluates arbitrary code to build or fetch a model (typically from the
|
||||||
# DB). If the step returns a falsy value, then the step will fail.
|
# DB). If the step returns a falsy value, then the step will fail.
|
||||||
#
|
#
|
||||||
|
@ -64,6 +64,18 @@ RSpec.describe ServiceRunner do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class FailureWithOptionalModelService
|
||||||
|
include Service::Base
|
||||||
|
|
||||||
|
model :fake_model, optional: true
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def fetch_fake_model
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class FailureWithModelErrorsService
|
class FailureWithModelErrorsService
|
||||||
include Service::Base
|
include Service::Base
|
||||||
|
|
||||||
@ -284,6 +296,14 @@ RSpec.describe ServiceRunner do
|
|||||||
BLOCK
|
BLOCK
|
||||||
|
|
||||||
context "when fetching a single model" do
|
context "when fetching a single model" do
|
||||||
|
context "when the service uses an optional model" do
|
||||||
|
let(:service) { FailureWithOptionalModelService }
|
||||||
|
|
||||||
|
it "does not run the provided block" do
|
||||||
|
expect(runner).not_to eq :no_model
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "when the service fails without a model" do
|
context "when the service fails without a model" do
|
||||||
let(:service) { FailureWithModelService }
|
let(:service) { FailureWithModelService }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user