From 5e09081513075445045ac4f170ae7c61b6774295 Mon Sep 17 00:00:00 2001 From: "Ben Sheldon [he/him]" Date: Sun, 9 Jul 2023 19:56:27 -0700 Subject: [PATCH] Add `GoodJob.configure_active_record` as alternative to `GoodJob.active_record_parent_class` --- README.md | 12 +++++++++++- app/models/{ => concerns}/good_job/lockable.rb | 0 app/models/good_job/active_record_parent_class.rb | 9 +++++++++ app/models/good_job/base_record.rb | 6 +++--- lib/good_job.rb | 15 ++++++++++++++- lib/good_job/engine.rb | 8 ++++++++ 6 files changed, 45 insertions(+), 5 deletions(-) rename app/models/{ => concerns}/good_job/lockable.rb (100%) create mode 100644 app/models/good_job/active_record_parent_class.rb diff --git a/README.md b/README.md index 00691382b..4679f7400 100644 --- a/README.md +++ b/README.md @@ -316,7 +316,17 @@ config.good_job.execution_mode = :external Good Job’s general behavior can also be configured via attributes directly on the `GoodJob` module: -- **`GoodJob.active_record_parent_class`** (string) The ActiveRecord parent class inherited by GoodJob's ActiveRecord model `GoodJob::Job` (defaults to `"ActiveRecord::Base"`). Configure this when using [multiple databases with ActiveRecord](https://guides.rubyonrails.org/active_record_multiple_databases.html) or when other custom configuration is necessary for the ActiveRecord model to connect to the Postgres database. _The value must be a String to avoid premature initialization of ActiveRecord._ +- **`GoodJob.configure_active_record { ... }`** Inject Active Record configuration into GoodJob's base model, for example, when using [multiple databases with ActiveRecord](https://guides.rubyonrails.org/active_record_multiple_databases.html) or when other custom configuration is necessary for the ActiveRecord model to connect to the Postgres database. Example: + + ```ruby + # config/initializers/good_job.rb + GoodJob.configure_active_record do + connects_to database: :special_database + self.table_name_prefix = "special_application_" + end + ``` + +- **`GoodJob.active_record_parent_class`** (string) Alternatively, modify the ActiveRecord parent class inherited by GoodJob's Active Record model `GoodJob::Job` (defaults to `"ActiveRecord::Base"`). Configure this _The value must be a String to avoid premature initialization of ActiveRecord._ You’ll generally want to configure these in `config/initializers/good_job.rb`, like so: diff --git a/app/models/good_job/lockable.rb b/app/models/concerns/good_job/lockable.rb similarity index 100% rename from app/models/good_job/lockable.rb rename to app/models/concerns/good_job/lockable.rb diff --git a/app/models/good_job/active_record_parent_class.rb b/app/models/good_job/active_record_parent_class.rb new file mode 100644 index 000000000..bb71753e3 --- /dev/null +++ b/app/models/good_job/active_record_parent_class.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module GoodJob + ActiveRecordParentClass = if GoodJob.active_record_parent_class + Object.const_get(GoodJob.active_record_parent_class) + else + ActiveRecord::Base + end +end diff --git a/app/models/good_job/base_record.rb b/app/models/good_job/base_record.rb index 0379bd0f3..c7e8c5856 100644 --- a/app/models/good_job/base_record.rb +++ b/app/models/good_job/base_record.rb @@ -1,13 +1,11 @@ # frozen_string_literal: true module GoodJob - ACTIVE_RECORD_PARENT_CLASS = Object.const_get(GoodJob.active_record_parent_class) - # Base ActiveRecord class that all GoodJob models inherit from. # Parent class can be configured with +GoodJob.active_record_parent_class+. # @!parse # class BaseRecord < ActiveRecord::Base; end - class BaseRecord < ACTIVE_RECORD_PARENT_CLASS + class BaseRecord < ActiveRecordParentClass self.abstract_class = true def self.migration_pending_warning! @@ -29,5 +27,7 @@ def self.migrated? migration_pending_warning! false end + + ActiveSupport.run_load_hooks(:good_job_base_record, self) end end diff --git a/lib/good_job.rb b/lib/good_job.rb index 449583d40..54f5e5968 100644 --- a/lib/good_job.rb +++ b/lib/good_job.rb @@ -47,7 +47,7 @@ module GoodJob # @return [ActiveRecord::Base] # @example Change the base class: # GoodJob.active_record_parent_class = "CustomApplicationRecord" - mattr_accessor :active_record_parent_class, default: "ActiveRecord::Base" + mattr_accessor :active_record_parent_class, default: nil # @!attribute [rw] logger # @!scope class @@ -106,6 +106,19 @@ def self._on_thread_error(exception) on_thread_error.call(exception) if on_thread_error.respond_to?(:call) end + # Custom Active Record configuration that is class_eval'ed into +GoodJob::BaseRecord+ + # @param block Custom Active Record configuration + # @retyrn [void] + # + # @example + # GoodJob.configure_active_record do + # connects_to database: :special_database + # end + def self.configure_active_record(&block) + self._active_record_configuration = block + end + mattr_accessor :_active_record_configuration, default: nil + # Stop executing jobs. # GoodJob does its work in pools of background threads. # When forking processes you should shut down these background threads before forking, and restart them after forking. diff --git a/lib/good_job/engine.rb b/lib/good_job/engine.rb index f094011ec..1e267c6be 100644 --- a/lib/good_job/engine.rb +++ b/lib/good_job/engine.rb @@ -40,6 +40,14 @@ class Engine < ::Rails::Engine end end + initializer 'good_job.active_record' do + config.to_prepare do + ActiveSupport.on_load :good_job_base_record, run_once: true do + GoodJob::BaseRecord.class_eval(&GoodJob._active_record_configuration) if GoodJob._active_record_configuration + end + end + end + initializer "good_job.start_async" do # This hooks into the hookable places during Rails boot, which is unfortunately not Rails.application.initialized? # If an Adapter is initialized during boot, we want to want to start async executors once the framework dependencies have loaded.