如果您能够控制和配置每个 Rails 实例,并且由于它们处于待机状态而浪费资源,那么您可以省去一些麻烦,只需更改 database.yml 以修改每个实例上使用的数据库连接。如果您担心性能,这种方法将无法解决问题。
对于绑定到仅在一个数据库上的单个唯一表的模型,您可以在模型内部调用建立连接:
establish_connection "database_name_#{RAILS_ENV}"
如此处所述:http://apidock.com/rails/ActiveRecord/Base/establish_connection/class
您将有一些模型使用来自一个数据库的表,而其他不同的模型使用来自其他数据库的表。
如果您有相同的表,在不同的数据库上通用,并且由单个模型共享,ActiveRecord 将无法帮助您。早在 2009 年,我在一个正在使用 Rails 2.3.8 的项目中需要这个。我为每个客户建立了一个数据库,并用他们的 ID 命名了这些数据库。所以我创建了一个方法来改变 ApplicationController 内部的连接:
def change_database database_id = params[:company_id]
return if database_id.blank?
configuration = ActiveRecord::Base.connection.instance_eval { @config }.clone
configuration[:database] = "database_name_#{database_id}_#{RAILS_ENV}"
MultipleDatabaseModel.establish_connection configuration
end
并将该方法作为 before_filter 添加到所有控制器:
before_filter :change_database
所以对于每个控制器的每个动作,当 params[:company_id] 被定义和设置时,它会将数据库更改为正确的。
为了处理迁移,我扩展了 ActiveRecord::Migration,使用一种查找所有客户并使用每个 ID 迭代块的方法:
class ActiveRecord::Migration
def self.using_databases *args
configuration = ActiveRecord::Base.connection.instance_eval { @config }
former_database = configuration[:database]
companies = args.blank? ? Company.all : Company.find(args)
companies.each do |company|
configuration[:database] = "database_name_#{company[:id]}_#{RAILS_ENV}"
ActiveRecord::Base.establish_connection configuration
yield self
end
configuration[:database] = former_database
ActiveRecord::Base.establish_connection configuration
end
end
请注意,通过这样做,您将不可能在同一操作中从两个不同的数据库进行查询。您可以再次调用 change_database,但是当您尝试使用不再链接到正确数据库的对象执行查询的方法时,它会变得很糟糕。此外,很明显您将无法连接属于不同数据库的表。
为了正确处理这个问题,应该大大扩展 ActiveRecord。现在应该有一个插件可以帮助您解决这个问题。一项快速研究给了我这个:
DB-Charmer:http://kovyrin.github.com/db-charmer/
我愿意尝试。让我知道什么对你有用。