rails: undefined method `pool when running a test with multiple databases on Rails 6.1

Steps to reproduce

I have a normal test to an endpoint that calls two different databases

    get '/api/rankings', params: {
      domain: 'example',
      tld: 'com',
      ranked_at: '20210220'
    }, headers: { authorization: 'Bearer XXXXX' }
    expect(response).to have_http_status(200)

database.yml

test:
  primary:
    <<: *default
    host: localhost
    port: 5432
    username: postgres
    password: postgres
    database: primary_test

  secondary:
    <<: *default
    host: localhost
    port: 5432
    username: postgres
    password: postgres
    database: secondary_test
    migrations_paths: db/secondary_migrate

Expected behavior

It should complete the test with no DB errors

Actual behavior

             get '/api/rankings', params: {
        domain: 'example',
        tld: 'com',
        ranked_at: '20210220'
      }, headers: { authorization: 'Bearer XXXXX' }
          
          NoMethodError:
            undefined method `pool' for nil:NilClass
          # <internal:kernel>:90:in `tap'
          # ./spec/requests/rankings_request_spec.rb:15:in `block (3 levels) in <top (required)>'

     1.2) Failure/Error: owner_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
          
          NoMethodError:
            undefined method `pool' for nil:NilClass
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:1035:in `map'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:1035:in `block in all_connection_pools'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:1035:in `each'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:1035:in `flat_map'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:1035:in `all_connection_pools'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_handling.rb:356:in `clear_on_handler'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_handling.rb:275:in `clear_query_caches_for_current_thread'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/query_cache.rb:21:in `rollback_db_transaction'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/transaction.rb:205:in `rollback'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/transaction.rb:302:in `block in rollback_transaction'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-6.1.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-6.1.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-6.1.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-6.1.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-6.1.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/transaction.rb:300:in `rollback_transaction'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/connection_adapters/abstract/database_statements.rb:328:in `rollback_transaction'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/test_fixtures.rb:168:in `block in teardown_fixtures'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/test_fixtures.rb:167:in `each'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/test_fixtures.rb:167:in `teardown_fixtures'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activerecord-6.1.3/lib/active_record/test_fixtures.rb:16:in `after_teardown'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/activejob-6.1.3/lib/active_job/test_helper.rb:52:in `after_teardown'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-rails-4.0.2/lib/rspec/rails/adapters.rb:76:in `block (2 levels) in <module:MinitestLifecycleAdapter>'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:390:in `execute_with'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:390:in `execute_with'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:629:in `run_around_example_hooks_for'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:486:in `run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:465:in `with_around_example_hooks'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:508:in `with_around_and_singleton_context_hooks'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:259:in `run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:644:in `block in run_examples'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:640:in `map'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:640:in `run_examples'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:606:in `run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `block in run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `map'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `block (3 levels) in run_specs'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `map'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `block (2 levels) in run_specs'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/configuration.rb:2067:in `with_suite_hooks'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:116:in `block in run_specs'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/reporter.rb:74:in `report'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:115:in `run_specs'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:89:in `run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:71:in `run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:45:in `invoke'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-core-3.10.1/exe/rspec:4:in `<top (required)>'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/bin/rspec:23:in `load'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/bin/rspec:23:in `<top (required)>'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/cli/exec.rb:63:in `load'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/cli/exec.rb:63:in `kernel_load'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/cli/exec.rb:28:in `run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/cli.rb:494:in `exec'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/cli.rb:30:in `dispatch'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/cli.rb:24:in `start'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/exe/bundle:49:in `block in <top (required)>'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/lib/bundler/friendly_errors.rb:130:in `with_friendly_errors'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bundler-2.2.9/exe/bundle:37:in `<top (required)>'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/bin/bundle:23:in `load'
          # /home/yknx4/.asdf/installs/ruby/3.0.0/bin/bundle:23:in `<main>'

System configuration

Rails version: 6.1.3

Ruby version: 3.0.0

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 25 (17 by maintainers)

Commits related to this issue

Most upvoted comments

A little confused on this one, we do have multiple databases (so it seems like “that’s not really a fix” would apply to us), and we aren’t using replicas. Different models come from different databases.

Sorry I meant multiple connection types. Your model in this example is using only a writing connection - so connects_to isn’t necessary. But if someone had replicas then using establish_connection won’t work.

This fixed it for us. image

I don’t really understand why, but once I got down into the code that was blowing up, and read the comments around there, I saw an example that did that, which worked (here).

In a very technical sense, we could see that this line was exploding because the pool config’s reading default was nil, even though I don’t really understand why that was the case.

Anyway, hope this is helpful.

@batalla3692 I fixed that in https://github.com/rails/rails/pull/45773. It was backported to 7-0-stable and 6-1-stable but only if you’re using the new connection handling. Opting into new handling (set config.active_record.legacy_connection_handling = false and fix any calls to connection_handlers) should be pretty simple if you haven’t already.

I came a little bit late to this issue, but I’ve been dealing with this very same error on test environement (although now it has a nicer error message thanks @eileencodes).

After reading the error message, I found that the error is raised when the order of the roles defined in the model is not exactly :writing first and then :reading

I had those roles inverted in my model, so the error was being triggered:

class AuditRecord < ActiveRecord::Base
  self.abstract_class = true
  connects_to database: { reading: :audit, writing: :audit }
end

But everything started to work after I changed the order to:

class AuditRecord < ActiveRecord::Base
  self.abstract_class = true
  connects_to database: { writing: :audit, reading: :audit }
end

@JonRowe @jdarnok Ok, @rails-bot is being a PITA so if you can come up with a reproduction script can you please open a new ticket? 🙇