diff --git a/plugins/chat/app/jobs/service_job.rb b/app/jobs/service_job.rb similarity index 100% rename from plugins/chat/app/jobs/service_job.rb rename to app/jobs/service_job.rb diff --git a/app/services/service/base.rb b/app/services/service/base.rb index 531169f44cd..08f60c6a487 100644 --- a/app/services/service/base.rb +++ b/app/services/service/base.rb @@ -139,13 +139,15 @@ module Service def call(instance, context) context[name] = super - raise ArgumentError, "Model not found" if !optional && context[name].blank? + if !optional && (!context[name] || context[name].try(:empty?)) + raise ArgumentError, "Model not found" + end if context[name].try(:invalid?) context[result_key].fail(invalid: true) context.fail! end rescue ArgumentError => exception - context[result_key].fail(exception: exception) + context[result_key].fail(exception: exception, not_found: true) context.fail! end end diff --git a/lib/service_runner.rb b/lib/service_runner.rb index 7dbec6e7a67..05c9f507709 100644 --- a/lib/service_runner.rb +++ b/lib/service_runner.rb @@ -80,7 +80,9 @@ class ServiceRunner default_name: "default", }, on_model_not_found: { - condition: ->(name = "model") { failure_for?("result.model.#{name}") && result[name].blank? }, + condition: ->(name = "model") do + failure_for?("result.model.#{name}") && result["result.model.#{name}"].not_found + end, key: %w[result model], default_name: "model", }, diff --git a/plugins/chat/spec/lib/service_runner_spec.rb b/spec/lib/service_runner_spec.rb similarity index 90% rename from plugins/chat/spec/lib/service_runner_spec.rb rename to spec/lib/service_runner_spec.rb index 9afa8d39722..bfd6eb653c4 100644 --- a/plugins/chat/spec/lib/service_runner_spec.rb +++ b/spec/lib/service_runner_spec.rb @@ -136,6 +136,18 @@ RSpec.describe ServiceRunner do end end + class RelationModelService + include Service::Base + + model :fake_model + + private + + def fetch_fake_model + User.where(admin: false) + end + end + describe ".call(service, &block)" do subject(:runner) { described_class.call(service, object, &actions_block) } @@ -145,7 +157,9 @@ RSpec.describe ServiceRunner do let(:actions) { "proc {}" } let(:object) do Class - .new(Chat::ApiController) do + .new(ApplicationController) do + include WithServiceHelper + def request OpenStruct.new end @@ -352,6 +366,34 @@ RSpec.describe ServiceRunner do end end end + + context "when fetching an ActiveRecord relation" do + let(:service) { RelationModelService } + + context "when the service does not fail" do + before { Fabricate(:user) } + + it "does not run the provided block" do + expect(runner).not_to eq :no_model + end + + it "does not fetch records from the relation" do + runner + expect(result[:fake_model]).not_to be_loaded + end + end + + context "when the service fails" do + it "runs the provided block" do + expect(runner).to eq :no_model + end + + it "does not fetch records from the relation" do + runner + expect(result[:fake_model]).not_to be_loaded + end + end + end end context "when using the on_model_errors action" do