diff --git a/server/app/interactors/authentication/signup.rb b/server/app/interactors/authentication/signup.rb index 0a4c1f0c5..0aa986c33 100644 --- a/server/app/interactors/authentication/signup.rb +++ b/server/app/interactors/authentication/signup.rb @@ -8,13 +8,14 @@ def call ActiveRecord::Base.transaction do create_new_user create_organization_and_workspace - + Rails.logger.info("[Signup] User email verification enabled: #{User.email_verification_enabled?}") user.skip_confirmation! unless User.email_verification_enabled? save_user if user.persisted? if User.email_verification_enabled? user.send_confirmation_instructions + Rails.logger.info("[Signup] Sending confirmation instructions to user: #{user.email}") context.message = "Signup successful! Please check your email to confirm your account." else context.message = "Signup successful!" diff --git a/server/config/initializers/appsignal_active_job_nil_transaction.rb b/server/config/initializers/appsignal_active_job_nil_transaction.rb new file mode 100644 index 000000000..e8643fa7f --- /dev/null +++ b/server/config/initializers/appsignal_active_job_nil_transaction.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +if defined?(Appsignal::Transaction) + Appsignal::Transaction.singleton_class.class_eval do + alias_method :create_without_string_id, :create + + def create(id, namespace, request, options = {}) + create_without_string_id(id.to_s, namespace, request, options) + end + end +end + +Rails.application.config.to_prepare do + next unless defined?(Appsignal::Hooks::ActiveJobHook::ActiveJobClassInstrumentation) + + safety_check = Module.new do + private + + def transaction_set_error(transaction, exception) + return unless Appsignal.config[:activejob_report_errors] == "all" + return if transaction.nil? + + transaction.set_error(exception) + end + end + + Appsignal::Hooks::ActiveJobHook::ActiveJobClassInstrumentation.prepend(safety_check) +end diff --git a/server/spec/config/initializers/appsignal_active_job_nil_transaction_spec.rb b/server/spec/config/initializers/appsignal_active_job_nil_transaction_spec.rb new file mode 100644 index 000000000..d24a91c9f --- /dev/null +++ b/server/spec/config/initializers/appsignal_active_job_nil_transaction_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe "Appsignal Active Job nil transaction fix (initializer)" do + before do + raise "Appsignal::Transaction not defined — is the gem loaded?" unless defined?(Appsignal::Transaction) + end + + describe "Transaction.create converts id to String" do + it "passes a string id to the original create (fails if monkey patch is removed)" do + expect(Appsignal::Transaction).to respond_to(:create_without_string_id), + "Appsignal::Transaction does not respond to :create_without_string_id — " \ + "the alias_method monkey patch in the initializer may have been removed" + + allow(Appsignal::Transaction).to receive(:create_without_string_id).and_return(nil) + + Appsignal::Transaction.create(123, :active_job, nil, {}) + + expect(Appsignal::Transaction).to have_received(:create_without_string_id) + .with("123", :active_job, nil, {}) + end + end + + describe "transaction_set_error with nil transaction" do + before do + unless defined?(Appsignal::Hooks::ActiveJobHook::ActiveJobClassInstrumentation) + raise "Appsignal::Hooks::ActiveJobHook::ActiveJobClassInstrumentation not defined " \ + "— is the appsignal gem loaded?" + end + end + + it "does not raise when transaction is nil (fails if monkey patch is removed)" do + instrumentation = Appsignal::Hooks::ActiveJobHook::ActiveJobClassInstrumentation + instance = Class.new { include instrumentation }.new + + expect(instance.private_methods).to include(:transaction_set_error), + "Expected instance to have private method :transaction_set_error — " \ + "the safety module may no longer be prepended in the initializer" + + exception = StandardError.new("job error") + allow(Appsignal).to receive(:config).and_return({ activejob_report_errors: "all" }) + + expect { instance.send(:transaction_set_error, nil, exception) }.not_to raise_error + end + end +end