Skip to content

Skip models connected to non-primary databases#237

Open
tmaier wants to merge 3 commits into
gregnavis:masterfrom
tmaier:149-approach-1
Open

Skip models connected to non-primary databases#237
tmaier wants to merge 3 commits into
gregnavis:masterfrom
tmaier:149-approach-1

Conversation

@tmaier

@tmaier tmaier commented Mar 18, 2026

Copy link
Copy Markdown

Summary

Fixes #149active_record_doctor crashes when the application has models
connected to a different database (e.g. a gem using establish_connection
to SQLite while the app uses PostgreSQL).

Root cause: Base#connection is hardcoded to ActiveRecord::Base.connection
(the primary database). When missing_non_null_constraint calls
models.select(&:table_exists?), it uses each model's own connection — so a
secondary-DB model returns true. Then connection.columns(table) queries the
primary connection for that table, which doesn't exist there → crash.

Fix: Filter Base#models to exclude models whose connection_pool differs
from ActiveRecord::Base.connection_pool. This is a single guard that protects
all detectors — no per-detector changes needed.

Changes

  • lib/active_record_doctor/detectors/base.rb — Filter models by connection pool
  • test/setup.rb — Add SecondaryContext for multi-DB tests; graceful adapter loading
  • test/.../missing_non_null_constraint_test.rb — Test: secondary-DB model doesn't crash
  • test/.../undefined_table_references_test.rb — Test: secondary-DB model isn't flagged
  • README.md — Document "Multiple Databases" behavior
  • Gemfile — Pin minitest ~> 5.0 (minitest 6 broke minitest-fork_executor)

Test plan

  • New tests fail without the fix (RED)
  • New tests pass with the fix (GREEN)
  • Full suite: 257 runs, 0 failures, 0 errors (39 adapter-specific skips)

Disclaimer: This PR was created with the help of AI

tmaier added 3 commits March 18, 2026 16:38
Pin minitest to ~> 5.0 in the Gemfile because minitest 6.0 removed
Minitest.run_one_method which minitest-fork_executor depends on.
Without the pin, bundle resolves to minitest 6.0.2 and the test
suite crashes on startup.

Make adapter requires in test/setup.rb graceful so the test suite
can run when only one database adapter gem is installed (e.g.
sqlite3 only). In CI all adapters are present, so this is a no-op
there.

Also add SecondaryContext (TransientRecord context for the existing
SecondaryRecord class) to enable writing tests that exercise
multi-database scenarios.
When a model uses establish_connection or connects_to to point at a
different database, detectors should silently skip it. Previously
they would crash (e.g. PG::UndefinedTable) because the detector
queried the primary connection for a table that only exists in the
secondary database.

Add two test cases using SecondaryContext:

- missing_non_null_constraint: a secondary-DB model with a nullable
  column and a presence validator must not crash the detector.
- undefined_table_references: a secondary-DB model must not be
  reported as referencing an undefined table.
All detectors use Base#models to discover ActiveRecord models, then
inspect their tables via Base#connection which is hardcoded to
ActiveRecord::Base.connection (the primary database).

When a model uses establish_connection or connects_to for a different
database, model.table_exists? returns true (checked against its own
connection), but connection.columns(table) crashes because the
primary database has no such table.

Fix by filtering Base#models to exclude models whose connection_pool
differs from ActiveRecord::Base.connection_pool. This is a single
guard that protects all detectors at once — no per-detector changes
are needed.

Document the limitation in the README under "Multiple Databases".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error when listing columns for model backed by different DB

1 participant