[Ruby] ActiveRecord で複数のデータベースに接続する方法

» Posted by on 2月 16, 2009 in Blog | 0 comments

時々1つのアプリケーションから複数のデータベースにアクセスする必要に迫られることがあります。
たとえば、他のアプリの作ったデータベースにアクセスしたい場合とか。
でも、ActiveRecord のサンプルプログラムのほとんどは、 ActiveRecord::Base に直接設定をセットしているし、
ActiveRecord::Base を使ってコネクションを作成しているので、複数のデータベースの接続を AR をつかって張ることができないです(やりにくい)。
ではどうするか?

ただ、ActiveRecord のサブクラスを作成するだけです。

ActiveRecord::Base のサブクラスは親クラスの読み込んだ設定や、データベースへの接続へアクセスできるので、
まず ActiveRecord::Base のサブクラスを作成して(ここでは BaseDB)これにデータベースの設定をセットします。
それから、 BaseDB を継承した子クラスを作って、その子クラスにそれぞれデータベースへの接続を張らせます。
たぶん、ActiveRecord::Base に直接設定をセットしたり、ActiveRecord::Base で直接データベースへの接続を張るよりも、
子クラスの方でなんとかした方が良さそうです。とくに将来複数のデータベースとかを扱う状況になるかもしれない場合・・・。

  • ActiveRecord::Base
    • BaseDB < ActiveRecord::Base (これにデータベースの設定などをセットする)
      • MyDB < BaseDB (これを使ってデータベース mydb への接続を張る)
      • YourDB < BaseDB (これを使ってデータベース yourdb への接続を張る)

下のサンプルコードが、異なる2つのデータベースに接続する例です。

想定している環境:

  • データベース(1)
    • databasename : my_db
    • username : myname
    • password : mypass
  • データベース(2)
    • databasename : your_db
    • username : yourname
    • password : yourpass

ディレクトリ構成:

  • bin/ar-multi-connections-test.rb : メインプログラム
  • config/database.yml : データベースの設定ファイル
  • lib/base_db.rb : *_db のベースクラスでデータベースの設定を保持するクラス
  • lib/my_db.rb : データベース(1) の my_db 用
  • lib/my_table.rb : データベース(1) のテーブル用
  • lib/your_db.rb : データベース(2) の your_db 用
  • lib/your_table.rb : データベース(2) のテーブル 用

コード

bin/ar-multi-connections-test.rb

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

$LOAD_PATH << File.expand_path(File.join('..', 'lib'), File.dirname(__FILE__))

require 'messa/engine/parser'
require 'messa/messa_helper'
require 'messa/logger_factory'

# path to database configuration file
config_file = File.expand_path(File.join('..', 'config', 'database.yml'), File.dirname(__FILE__))

BaseDB.load_database_configurations(config_file)

MyDB.establish_connection(:mydb_test)
YourDB.establish_connection(:yourdb_test)

config/database.yml

mydb_test:
  adapter: mysql
  encoding: utf8
  database: mydb
  username: myname
  password: mypass
  socket: /var/run/mysqld/mysqld.sock

yourdb_test:
  adapter: mysql
  encoding: utf8
  database: yourdb
  username: yourname
  password: mypass
  socket: /var/run/mysqld/mysqld.sock

lib/base_db.rb

# -*- coding: utf-8 -*-

require 'rubygems'
require 'activerecord'
require 'erb'
require 'yaml'

class BaseDB < ActiveRecord::Base
  #
  #=== load configurations from YAML file
  #
  #_config_ :: path to a YAML configuration file
  #
  def self.load_configurations(config)
    # like ActiveRecord::Base.configurations = ...
    self.configurations = YAML::load(ERB.new(IO.read(config)).result)
  end # def
end # class

lib/my_db.rb

# -*- coding: utf-8 -*-

require 'base_db'

class MyDB < BaseDB
end # class

lib/my_table.rb

# -*- coding: utf-8 -*-

require 'my_db'

class MyTable < MyDB
  set_table_name 'my_table'
end # class

lib/your_db.rb

# -*- coding: utf-8 -*-

require 'base_db'

class YourDB < BaseDB
end

lib/your_table.rb

# -*- coding: utf-8 -*-

require 'your_db'

class YourTable < YourDB
  set_table_name 'your_table'
end # class

これだけです。