34
votes

This code was taken from ActiveRecord 2.3.14's gem class ConnectionHandler

def establish_connection(name, spec)
  @connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
end

It seems each time ruby calls establish_connection on the model, it's creating a new connection pool.

My question:

If I have 5 models that use establish_connection to the same database, is Rails smart enough to pick an already existing pool rather creating a new one with the same connection credentials? Does this also happen if my 5 models are subclasses of some abstract class that uses establish_connection? Will it always pick a connection from the @connection_pools if it exists?

Update 1

I'm talking about a concrete example. You have 5 models with 5 different connections, each time Rails uses a model it executes establish_connection. Looking at the code in ActiveRecord, when it executes establish_connection it creates a new pool with connections to that specific connection. What I'm wondering is whether each time Rails calls a model's establish_connection, does it create a new pool or take the existing one.

Example: you come to my site and see a product list. You've just hit an action that calls Product.all, which executes establish_connection to some database on Amazon. Then, I come to the product list, what happens? Do I grab the established connection or am I creating a new pool with that connection?

Update 2

My guess is that first time Rails loads my models it's creating pools with different connections. After, when I use some Model.method, it just grabs the connection associated with the model and executes the method.

I'm not sure what happens when 2 models have two equal connections (not in the abstract class but in self class). Will this produce two same connection pools, or is ActiveRecord smart enough to catch this case?

3
BTW, very good question.bor1s

3 Answers

9
votes

You really do not have to call establish_connection on each model. You can simply do next:

ActiveRecord::Base.establish_connection(
 { :adapter => 'mysql2',
   :database => 'some_database',
   :host => 'localhost',
   :username => 'root',
   :password => "" }
)

and you will have access to connection. (This chunk of code has been extracted from real code(except database name :) )).
But according to API I think that Rails does not take existing connection from other model (correct me if I am wrong).
Also here is a link to documentation. You can read more about the connection there.
I hope I helped you alittle.

18
votes

AR calls establish_connection only once, for ActiveRecord::Base. All subclasses use the one connection.

You can manually call establish connection yourself on some subclasses. This is very convenient for using two databases at once, e.g.

class MyMainUser < ActiveRecord::Base; end 
class MyOtherDb < ActiveRecord::Base; end
class MyOtherUser < MyOtherDb; end

MyOtherDb.establish_connection ...

MyMainUser.first # uses default db
MyOtherUser.first # uses other db

You can't do queries that would cross databases though.

3
votes

This comment:

# Check-out a database connection from the pool, indicating that you want
# to use it. You should call #checkin when you no longer need this.
#
# This is done by either returning an existing connection, or by creating
# a new connection. If the maximum number of connections for this pool has
# already been reached, but the pool is empty (i.e. they're all being used),
# then this method will wait until a thread has checked in a connection.
# The wait time is bounded however: if no connection can be checked out
# within the timeout specified for this pool, then a ConnectionTimeoutError
# exception will be raised.

from: https://github.com/rails/rails/blob/dd944cbf5879e675fff541d1be7c7eb6c3382d01/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L242-251

Should explain the situation