Multiple Concurrent Database Connections with ActiveRecord

ActiveRecord is a great tool to use for database maintenance as I explored in my previous article, Using ActiveRecord for Simple Maintenance Scripting, but what if you need to do tasks that require you to be connected to multiple databases at once.

Perhaps you want to compare records in one database and copy them to another, well heres how you do it.

Configuration

Setup a database.yml file to contain your different database configurations.

database.yml

database_1:
  adapter: mysql
  host: db1.host
  username: johnny 
  password: secret
  database: db1

database_2:
  adapter: mysql
  host: db2.host
  username: johnny 
  password: secret
  database: db2

Setup database connections

Create a class for each database connection. The establish_connection method will load your YAML config for the desired database. Your models will inherit from these classes.

require 'active_record'

$config = YAML.load_file(File.join(File.dirname(__FILE__), 'database.yml'))

class DatabaseA < ActiveRecord::Base
  establish_connection $config['database1']
end

class DatabaseB < ActiveRecord::Base
  establish_connection $config['database2']
end

Prepare Models

It is a good idea to separate each group of database models into its own module to avoid namespace clashes. In this example I have two databases which have the same schema (a production and development database perhaps). Each model must inherit from the Database class it belongs to, in this example either DatabaseA or DatabaseB.

module A
  class Person < DatabaseA
    has_one :email
  end

  class Email < DatabaseA
    belongs_to :person
  end
end

module B
  class Person < DatabaseB
    has_one :email
  end

  class Email < DatabaseB
    belongs_to :person
  end
end

Separating the models into 2 different modules allows us to reference the same model name across multiple databases without colliding namespaces. eg. A::Person and B::Person.

Usage

For whatever reason I ended up having person records stored in my development database and I need them copied over to a production database.
The problem is that each person record has associated table data, in this case an emails table which must also be copied over with each record.

Copy a person from one database to another

First we will gank a person from the Database A (or development db) specifying the :include parameter in the finder args so that the email association is also stored in our receiving person object.

Now that the person is copied we can make a new person specifying the Database B::Person model with the ganked person.attributes as our begining params.

Next we can build associations, in this case the email association with the build_email method.

When saving all primary and foreign keys will be reset to the new record’s id.

  person = A::Person.find_by_name('Corban Brook', :include => [:email])
  
  new_person = B::Person.new person.attributes
  new_person.build_email person.email.attributes
  new_person.save

I would like to thank tshine from #radrails for his help.



About this entry


About

    Buildingsky.net is comprised of a group of computer science enthusiasts. We build, experiment and learn together.

    We are interested in HTML5, Ruby, Javascript, DSP, and finance/economics.

Contact

Projects

Categories