Skip to content

youichiro/rails-multiple-db-sandbox

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rails-multiple-db-sandbox

Rails6からActiveRecordで複数のデータベースが利用できるようになったので試す
参考:Railsガイド|Active Record で複数のデータベース利用

やったこと

  • 複数のデータベースを作成
    • commonデータベースとschoolデータベース
  • primary/replicaデータベースを利用
    • commonデータベースのreplicaと、schoolデータベースのreplica
  • GETリクエストはreplicaが呼び出されることを確認
  • 異なるデータベースのテーブル間のJOINはできないことを確認

バージョン

  • ruby 2.7.1
  • rails 6.0.3.4

データベース構成

image

セットアップ

$ git clone https://github.com/youichiro/rails-multiple-db-sandbox.git
$ cd rails-multiple-db-sandbox
# config/database.ymlのpasswordやportなどを編集
$ bin/rails db:create
$ bin/rails db:migrate
$ bin/rails db:seed

新しいモデルを追加する手順

schoolデータベースにTeacherモデルを追加する手順の例

generame model

$ bin/rails g model teacher name:string --database school

Running via Spring preloader in process 54763
      invoke  active_record
      create    db/school_migrate/20201030135726_create_teachers.rb
      create    app/models/teacher.rb
      invoke    test_unit
      create      test/models/teacher_test.rb
      create      test/fixtures/teachers.yml

--databaseでschoolデータベースを指定することでdb/school_migrateディレクトリにマイグレーションファイルが作成される

モデルの継承クラスを変更

デフォルトではApplicationRecordを継承しているが、Schoolデータベースを使用したいのでSchoolBaseを継承するように変更する

- class Teacher < ApplicationRecord
+ class Teacher < SchoolBase
  end

db:migrate

# 全てのマイグレーションファイルを適用する場合
$ bin/rails db:migrate

# schoolデータベースのマイグレーションファイルのみを適用する場合
$ bin/rails db:migrate:school

リクエストによってprimary/replicaが切り替わっているかの確認

replicaを用意することでPOST, PUT, DELETE, PATCHのリクエストはprimaryに書き込み、GET, HEADリクエストはreplicaから読み込むようになる
これを確認するために、arproxyを使用してクエリのログにデータベースの接続状況を表示するようにする

arproxyの設定

  • Gemfilegem arproxyを追加してbundle install
  • config/initializers/arproxy.rbに以下を記述
if Rails.env.development? || Rails.env.test?
 require 'multiple_database_connection_logger'
 Arproxy.configure do |config|
   config.adapter = 'mysql2'
   config.use MultipleDatabaseConnectionLogger
 end
 Arproxy.enable!
end
  • lib/multiple_database_connection_logger.rbに以下を記述
class MultipleDatabaseConnectionLogger < Arproxy::Base
 def execute(sql, name = nil)
  role = ActiveRecord::Base.current_role
  name = "#{name} [#{role}]"
  super(sql, name)
 end
end

リクエスト時のデータベース接続状況を確認

curlからリクエストを送信してログを見ると、呼び出されたデータベースとwritingかreadingかが表示される

index

$ curl localhost:3000/schools

image

show

$ curl localhost:3000/schools/1

image

create

$ curl -X POST -H 'Content-Type: application/json' -d '{"name": "school2"}' localhost:3000/schools

image

update

$ curl -X PUT -H 'Content-Type: application/json' -d '{"name": "school1(updated)"}' localhost:3000/schools/1

image

destroy

$ curl -X DELETE http://localhost:3000/schools/3

image

JOIN

同じデータベースのテーブル間はJOINできる

studentsテーブルをgradeテーブルにJOINする場合

Grade.joins(:students).where(name: 'grade1')

発行されるSQL

SELECT `grades`.*
FROM `grades`
INNER JOIN `students` ON `students`.`grade_id` = `grades`.`id`
WHERE `grades`.`name` = 'grade1

異なるデータベースのテーブル間はJOINできない

studentsテーブルをusersテーブルにJOINしようとした場合

User.joins(:students).where(name: 'ogawa')

発生するエラー

ActiveRecord::StatementInvalid (Mysql2::Error: Table 'rails_app_common_development.students' doesn't exist)

About

Railsで複数DBを利用するサンプルコード

Topics

Resources

Stars

Watchers

Forks

Languages