はじめに
Rails6では、標準で複数DB接続がサポートされるようですね。。。早く使いたい。。。
Rails5のプロジェクトで、別DBから情報を引っ張ってきたいという要件があったので、試してみました。
ポイント
複数DBを扱うに当たって、めんどくさいことはマイグレーションでしょう。
今回は、別サービスから別サービスのDBへ単純に参照したいという要件なので、シンプルに行きます。
マイグレーション自体も、頑張れば複数DB用に管理できますが、結構めんどくさいです。
あと、Railsに慣れていると勘違いしてしまうかもしれませんが、Active Record自体はマイグレーションは必要ありません。
接続情報さえあれば、基本的にはいつも通り使えます。
データベース
今回は、こんな感じのテーブルがある感じです。
mysql> desc users;
+-------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| email_verified_at | timestamp | YES | | NULL | |
| password | varchar(255) | NO | | NULL | |
| remember_token | varchar(100) | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------------+---------------------+------+-----+---------+----------------+
Gemを入れる
今回は、実験的にシンプルなRubyプロジェクトからDBをActive Recordを使って参照してみます。
あと、適当にMysql2を入れときます。テスト用に立てたMariaDBに繋いでみたんですが、普通に繋がりますね。
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem 'activerecord'
gem 'mysql2'
別DB接続用のクラスを作る
それでは、やっていきます。
ActiveRecord::Base#establish_connectionに接続情報を渡してやれば、使えるわけですが
ベストプラクティスとしては、やはり別DB接続用の抽象クラスを作っておくことでしょうか。
require 'bundler/setup'
require 'active_record'
class Connector < ActiveRecord::Base
self.abstract_class = true
con = {
adapter: 'mysql2',
host: 'your_db_host',
username: 'root',
password: 'password',
database: 'test_db'
}
establish_connection(con)
end
したら、こいつを継承した具象クラスを作ります。
これに関しては、ActiveRecordの命名規則に従うなり、オプションでテーブル名を指定するなりしてやってください。
require './connector.rb'
class User < Connector
scope :id, -> (id) { where(id: id) if id.present? }
end
動作確認
irbで動作確認してみます。
> irb
irb(main):001:0> require './user.rb'
=> true
irb(main):002:0> User.count
=> 2
irb(main):003:0> User.first
=> #<User id: 1, name: "test", email: "test@test.org", email_verified_at: nil, password: "password", remember_token: nil, created_at: "2019-06-17 00:00:00", updated_at: nil>
irb(main):004:0> user = User.new(id: 3, name: 'from active record', email: 'active_record@test.org', password: 'password')
=> #<User id: 3, name: "from active record", email: "active_record@test.org", email_verified_at: nil, password: "password", remember_token: nil, created_at: nil, updated_at: nil>
irb(main):005:0> user.save!
=> true
irb(main):006:0> User.count
=> 3
irb(main):007:0> User.id(1)
=> #<ActiveRecord::Relation [#<User id: 1, name: "test", email: "test@test.org", email_verified_at: nil, password: "password", remember_token: nil, created_at: "2019-06-17 00:00:00", updated_at: nil>]>
irb(main):008:0> User.find(1).email
=> "test@test.org"
いいですね、普通に動きました。
普通にActive Recordとしても使えますし、コネクションだけ用意して生SQL叩くとかの使い方も考えられますね。
参考
ActiveRecordを単体で使うには
複数のDBにまたがるRailsの運用方法まとめ
ActiveRecordで生SQLを使いたいときに便利なメソッド達