单个Rails APP中多数据库的处理

学习 为Rails 配置外部数据库。

场景描述

Rails中,有model user和 article,article与user的关系是一对多,现在需要针对每一个User,列出所有ta发布的文章,而 article的数据来源于另一个外部的数据库,比如 works 。

怎么处理?

用establish_connection。

解决方法

拆解成两步:

  • 为外部数据库建配置文件
  • 为model和外部数据库建立连接

具体如下:

Step1、 新增文件config/works_database.yml,内容如下:

# using another database
default: &default
  adapter: mysql2
  encoding: utf8
  username: root
  password:
  host: localhost
  pool: 5

development:
  <<: *default
  database: works_development

test:
  <<: *default
  database: works_test

production:
  <<: *default
  database: works_production

这里,假定数据库works_development是已经存在的,其实就是场景描述中的works数据库。

Step2、创建initializer去读取配置文件并存入环境变量中

在config/initializers/下,新增文件works_database.rb,内容如下:

WORKS_DB = YAML.load_file(File.join(Rails.root.join('config','works_database.yml')))[Rails.env.to_s]

这样,我们外部数据库的配置信息就会存储在WORKS_DB中了。

Step3、 创建一个基类来处理数据库的连接

新建文件app/models/works_database.rb,放入以下内容:

class WorksDatabase < ApplicationRecord
  self.abstract_class = true
  establish_connection WORKS_DB
end

establish_connection是ActiveRecord::Base的一个类方法,由于WorksDatabase继承自ApplicationRecord,所以可以直接调用,它的作用就是用于连接数据库的。

Step4、 将需要连接到WORKS_DB的model都继承自WorksDatabase

修改app/models/article.rb

class Article < WorksDatabase
  belongs_to :user
end

OK !

Step 3 和Step 4其实可以合并成一步,直接在app/models/article.rb中修改成如下:

class Article < ActiveRecord::Base
  belongs_to :user
  establish_connection WORKS_DB
end  

但是这种一般在只有一个或少数几个model需要用到外部数据库时使用的较多,当存在多个models的时候,则推荐用baseclass的方式,把establish_connection封装起来,其他类直接继承该基类即可。即遵守DRY原则。

参考

Managing Multiple Databases in a Single Rails Application