仅在块中建立与另一个数据库的连接?

在rails应用程序中,我在纯ruby中有这个代码:

class LinkCreator attr_accessor :animal def initialize(animal:) @animal = animal end def call "something#{link_id}" end private def link_id connection.execute(sql_request).first.first end def sql_request "SELECT field FROM table WHERE field_id = '#{field_id}' LIMIT 1" end def field_id animal.field_id end def connection ActiveRecord::Base.establish_connection( adapter: "mysql", host: ENV["MYSQL_HOST"], username: ENV["MYSQL_USERNAME"], password: ENV["MYSQL_PASSWORD"], database: ENV["MYSQL_DB_NAME"] ).connection end end 

如您所见,这不是一个模型,只是一个简单的类。 问题在于,更改了activerecord的连接,以及稍后在新连接上执行的其他请求。

是否可以仅在块中建立连接并返回到旧连接。 我知道我可以建立另一个连接,但这对性能非常不利。

如果将所有数据库连接保存在database.yml那将是很好的

 development: adapter: mysql2 other stuff... db_2: adapter: mysql2 other stuff.. other_envs: ..... 

然后创建一个类

 class OtherDB < ActiveRecord::Base establish_connection(:db_2) end 

从你的控制器你可以访问就像

 OtherDB.table_name = "table_name" OtherDB.first 

在这里查看我的博客http://imnithin.in/multiple-database.html

您可以在块中执行一些查询。 首先,定义一些扩展ActiveRecord的模块,如下所示。 这是生产中用于更改每个请求的数据库连接以及临时切换数据库以在另一个数据库中执行某些查询的代码的一部分。

 # RAILS_ROOT/lib/connection_switch.rb module ConnectionSwitch def with_db(connection_spec_name) current_conf = ActiveRecord::Base.connection_config begin ActiveRecord::Base.establish_connection(db_configurations[connection_spec_name]).tap do Rails.logger.debug "\e[1;35m [ActiveRecord::Base switched database] \e[0m #{ActiveRecord::Base.connection.current_database}" end if database_changed?(connection_spec_name) yield ensure ActiveRecord::Base.establish_connection(current_conf).tap do Rails.logger.debug "\e[1;35m [ActiveRecord::Base switched database] \e[0m #{ActiveRecord::Base.connection.current_database}" end if database_changed?(connection_spec_name, current_conf) end end private def database_changed?(connection_spec_name, current_conf = nil) current_conf = ActiveRecord::Base.connection_config unless current_conf current_conf[:database] != db_configurations[connection_spec_name].try(:[], :database) end def db_configurations @db_config ||= begin file_name = "#{Rails.root}/config/database.yml" if File.exists?(file_name) || File.symlink?(file_name) config ||= HashWithIndifferentAccess.new(YAML.load(ERB.new(File.read(file_name)).result)) else config ||= HashWithIndifferentAccess.new end config end end end ActiveRecord.send :extend, ConnectionSwitch 

现在你可以使用它如下:

 ActiveRecord.with_db("db_connection_name") do # some queries to another db end 

在activerecord / test / support / connection_helper.rb的 Rails代码库中找到了最简短的例子并略微适应:

 def with_another_db(another_db_config) original_connection = ActiveRecord::Base.remove_connection ActiveRecord::Base.establish_connection(another_db_config) yield ensure ActiveRecord::Base.establish_connection(original_connection) end 

用法(假设您在database.ymlanother_db:部分):

 with_another_db(ActiveRecord::Base.configurations['another_db']) do ActiveRecord::Base.connection.execute("SELECT 'Look ma, I have changed DB!';") end 

我使用从Heroku的DATABASE_URL获取的环境变量来连接到不同的数据库:

 class Database def self.development! ActiveRecord::Base.establish_connection(:development) end def self.production! ActiveRecord::Base.establish_connection(ENV['PRODUCTION_DATABASE']) end def self.staging! ActiveRecord::Base.establish_connection(ENV['STAGING_DATABASE']) end end 

例如:

 Database.production!; puts User.all.map(&:name) Database.staging!; puts User.all.map(&:name) 

使用实例变量来存储连接可能会有所帮助。 像这样的东西:

 def connection @connection ||= ActiveRecord::Base.establish_connection( adapter: "mysql", host: ENV["MYSQL_HOST"], username: ENV["MYSQL_USERNAME"], password: ENV["MYSQL_PASSWORD"], database: ENV["MYSQL_DB_NAME"] ).connection end 

这样,在将来的连接尝试中检索现有连接,而不是建立新连接。