diff --git a/Gemfile b/Gemfile index bb94df82..95a1c679 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,6 @@ source "https://rubygems.org" gemspec + +# minitest 6.0 removed run_one_method which minitest-fork_executor depends on +gem "minitest", "~> 5.0" diff --git a/README.md b/README.md index 7cc55885..14154b69 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,16 @@ ActiveRecordDoctor.configure do end ``` +### Multiple Databases + +`active_record_doctor` currently only analyzes models connected to the primary +database. Models that use a different database connection — whether via +`establish_connection`, `connects_to`, or by inheriting from an abstract class +with its own connection — are automatically skipped by all detectors. + +This means that if you have gems or parts of your application that connect to a +secondary database, their models won't be checked and won't cause errors. + ### Indexing Unindexed Foreign Keys Foreign keys should be indexed unless it's proven ineffective. However, Rails diff --git a/lib/active_record_doctor/detectors/base.rb b/lib/active_record_doctor/detectors/base.rb index b02630ba..df253d2e 100644 --- a/lib/active_record_doctor/detectors/base.rb +++ b/lib/active_record_doctor/detectors/base.rb @@ -156,7 +156,10 @@ def check_constraints(table_name) end def models - ActiveRecord::Base.descendants.sort_by(&:name) + base_pool = ActiveRecord::Base.connection_pool + ActiveRecord::Base.descendants + .reject { |model| model.connection_pool != base_pool } + .sort_by(&:name) end def underscored_name diff --git a/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb b/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb index 675a017f..c1977ffc 100644 --- a/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb +++ b/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb @@ -349,4 +349,17 @@ def test_created_on_updated_on_with_null_are_disallowed add `NOT NULL` to users.updated_on - timestamp columns are set automatically by Active Record and allowing NULL may lead to inconsistencies introduced by bulk operations OUTPUT end + + def test_models_with_non_primary_connection_are_skipped + # Models connected to a secondary database should be silently skipped. + # Previously this would crash with e.g. PG::UndefinedTable when the + # secondary table didn't exist in the primary database (see #149). + SecondaryContext.create_table(:users) do |t| + t.string :name, null: true + end.define_model do + validates :name, presence: true + end + + refute_problems + end end diff --git a/test/active_record_doctor/detectors/undefined_table_references_test.rb b/test/active_record_doctor/detectors/undefined_table_references_test.rb index 4176e089..e4553c06 100644 --- a/test/active_record_doctor/detectors/undefined_table_references_test.rb +++ b/test/active_record_doctor/detectors/undefined_table_references_test.rb @@ -52,4 +52,12 @@ def test_global_ignore_tables refute_problems end + + def test_models_with_non_primary_connection_are_skipped + # Models connected to a secondary database should be silently skipped, + # not reported as referencing undefined tables (see #149). + SecondaryContext.create_table(:users).define_model + + refute_problems + end end diff --git a/test/setup.rb b/test/setup.rb index 6be93235..f9445421 100644 --- a/test/setup.rb +++ b/test/setup.rb @@ -8,9 +8,11 @@ require "logger" require "active_record" -require "pg" -require "mysql2" -require "sqlite3" +%w[pg mysql2 sqlite3].each do |adapter_gem| + require adapter_gem +rescue LoadError + # Not all adapters need to be installed; only the one matching DATABASE_ADAPTER is required. +end adapter = ENV.fetch("DATABASE_ADAPTER") @@ -91,6 +93,8 @@ class SecondaryRecord < ApplicationRecord SecondaryRecord.establish_connection :secondary +SecondaryContext = TransientRecord.context_for SecondaryRecord + if ActiveRecord.version >= Gem::Version.new("7.1") # See https://github.com/rails/rails/pull/46522 for details. # When `false` (default in Rails 7.1) - validate presence only when the foreign key changed.