4
0

【Rails】既存の外部DBに接続してデータ取得をしてみた

Posted at

はじめに

開発チームのメンバーとともに、Railsを利用して外部DBの絡む案件開発を進めていました

問題点

既存の外部DBからActiveRecordを利用してデータ取得を行いたいが、方法が分からないという場面に遭遇しました

解決法

database.ymlへの追記

まず、database.ymlに外部DBについての記述を追加する必要がありました。
今回は「外部DBが、アプリケーションで利用しているDBと同じRDSインスタンス内に存在している」という状況でしたので、以下の記載例のような形で接続情報を共有している状態とします。
また今回はデータ取得のみが目的で、Railsから外部DBを管理したいという意図はなかったため、database_tasks:falseを設定しました。

database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  username: user
  password: password
  host: host

development:
  app:
    <<: *default
    database: app_development
  external:
    <<: *default
    database: external_db
    database_tasks: false
    
test:
  app:
    <<: *default
    database: app_test
  external:
    <<: *default
    database: external_db
    database_tasks: false

production:
  app:
    <<: *default
    database: app_production
  external:
    <<: *default
    database: external_db
    database_tasks: false

外部DBが完全に別物である場合(こちらの場面の方が多いかと思います)、例えば以下のように接続情報を分けて記載することで対応が可能なようです。

database.yml
main: &main
  adapter: mysql2
  encoding: utf8mb4
  username: user
  password: password
  host: host

external: &external
  adapter: mysql2
  encoding: utf8mb4
  username: external_user
  password: external_password
  host: otherhost
  database_tasks: false

development:
  app:
    <<: *main
    database: app_development
  external:
    <<: *external
    database: external_db

test:
  app:
    <<: *main
    database: app_test
  external:
    <<: *external
    database: external_db
    
production:
  app:
    <<: *main
    database: app_production
  external:
    <<: *external
    database: external_db

外部DB用抽象クラスの作成

database.ymlへの記載が完了したら、以下のように新たな抽象クラスを作成...というと私はすぐにピンと来なかったのですが、いわば「外部DB用のApplicationRecord」のような存在を作成してあげることで各種取り回しが容易となります。

app/model/application_external_record.rb
class ApplicationExternalRecord < ApplicationRecord
  # 引き継ぎたくないものがある場合、継承元はActiveRecord::Baseに
  # 抽象クラスとして設定
  self.abstract_class = true

  # 外部DBを使用するように設定(database.yml内の記述と対応)
  establish_connection :external_db
  
  # DBのライター/リーダーのエンドポイントが明確に分かれている場合などは以下の記法が適している
  # connects_to database: { writing: :external_db, reading: :external_db }
end

外部DBの各テーブルに対応するmodelの作成

先ほど作成した抽象クラスを継承する形で外部DB上のお目当てのテーブルに対応するmodelを作成していきます。
ここまでの作業が上手く行けば、例えばExternalTest.allといった記述によるデータ取得が可能となります。
必要であれば、外部DBと紐付けたmodel同士の関連付けも設定可能です。

app/model/application_external_record.rb
class ExternalTest < ApplicationExternalRecord
  # デフォルトではクラス名に基づいて外部DB上のexternal_testテーブルを見に行こうとしてしまう..
  # self.table_nameによってテーブル名を指定できる。テーブル名が大文字である場合などにも有効
  self.table_name = 'TEST'

  # has_many external_test_details
end

おわりに

今回の対応を通してdatabase.ymlの記法やApplicationRecord周りの挙動等、当初の問題と直接絡まない部分についても様々な学びを得ることが出来たと感じています🍀

参考にさせていただいた記事など

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0