I'm trying to upgrade the ActiveRecord gem to the latest 3.1.0 release and seeing a lot of exceptions being raised, I think it's due to how we handle multiple databases.
For each of our databases we specify a separate base class which inherits from ActiveRecord::Base
, and call establish_connection
in there. There are no cross-database relations. This has worked fine for us up until now.
Having upgraded to ActiveRecord 3.1.0 I'm seeing that it fails with an ActiveRecord::ConnectionNotEstablished
exception, when traversing relations (i.e. it will successfully pull a single entity or set of them from the DB, but fails when navigating to a related class).
The top line of the backtrace is C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.1.0/lib/active_record/connection_adapters/abstract/connection_pool.rb:410:in 'retrieve_connection'
, so I dug into this a little. The method is defined as follows:
def retrieve_connection(klass) #:nodoc:
pool = retrieve_connection_pool(klass)
(pool && pool.connection) or raise ConnectionNotEstablished
end
My simple test (puts Customer.first.address
) calls retrieve_connection
3 times. Twice with Customer
as the klass
parameter, and once with ActiveRecord::Base
as the parameter - which is when it fails as establish_connection
has not been called for ActiveRecord::Base
.
To the actual question then - is there a new recommended way of handling multiple database connections in ActiveRecord? If so, what is it?
If not, what could be causing this problem?
I ran into the same issue yesterday while upgrading to ActiveRecord 3.1.0. I can't speak to whether there is a new recommended way of handling multiple database connections in ActiveRecord 3.1, but I did find a way to unblock myself.
It appears a connection must now be established on ActiveRecord::Base in order for it to determine the table name lengths/rules of the adapter. Along with the rest of my connections established in my database initializer, I now also have an ActiveRecord::Base connection established to one of my DBs (it doesn't matter which one).
I'd like to think there's a better solution to be found, but I'm happy to be unblocked for now.
I am using this solution - What I was seeing was that when establish_connection was called in each of the OtherDb classes - there seemed to be alot of overhead reloading table definitions and I would randomly see issues every time the class def was reloaded.
# The idea here is to specify that a given model should use another
# database without having to change the entire inheritance hierarchy
# declare model for table in primary connection
class Bar < ActiveRecord::Base
# assume we have logic here that we don't want to refactor into a module
# but we do want to inherit in OtherDb::Bar
end
module Foo
# base model in Foo namespace - uses another db
class BaseConnection < ActiveRecord::Base
# OtherDb::Title.database contains a db config hash
# This would probably go in the initializers
establish_connection OtherDb::Title.database
end
# module used to override db connection
module OtherDb::Base
def retrieve_connection
# connection_handler.retrieve_connection(self) # normal behavior
connection_handler.retrieve_connection(Foo::BaseConnection) # use db from Foo::BaseConnection
end
end
# Foo::Bar is identical to ::Bar but is in another db
class Bar < ::Bar
extend OtherDb::Base
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With