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

Dou*_*gui 10 ruby ruby-on-rails

在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
Run Code Online (Sandbox Code Playgroud)

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

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

Nit*_*hin 18

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

development:
  adapter: mysql2
  other stuff...

db_2:
  adapter: mysql2
  other stuff..

other_envs:
.....
Run Code Online (Sandbox Code Playgroud)

然后创建一个类

class OtherDB < ActiveRecord::Base
  establish_connection(:db_2)
end
Run Code Online (Sandbox Code Playgroud)

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

OtherDB.table_name = "table_name"
OtherDB.first
Run Code Online (Sandbox Code Playgroud)

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


ble*_*ump 8

您可以在块中执行一些查询.首先,定义一些扩展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
Run Code Online (Sandbox Code Playgroud)

现在你可以使用它如下:

ActiveRecord.with_db("db_connection_name") do
  # some queries to another db
end
Run Code Online (Sandbox Code Playgroud)

  • @NoobieCorrect,这段代码不是线程安全的。更改 ActiveRecord::Base 连接会影响所有线程。您需要为附加数据库创建一个新的“ActiveRecord::ConnectionAdapters::ConnectionPool”,然后您可以将代码包装在“my_conn_pool.with_connection”块中。 (2认同)

Env*_*vek 5

已在Rails代码库中的activerecord / test / support / connection_helper.rb找到了最简短的示例,并稍作改动:

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
Run Code Online (Sandbox Code Playgroud)

用法(假设您的中有another_db:部分database.yml):

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