Ruby on rails 是否仅在块中建立与另一个数据库的连接?

Ruby on rails 是否仅在块中建立与另一个数据库的连接?,ruby-on-rails,ruby,Ruby On Rails,Ruby,在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

在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的连接发生了更改,其他请求随后在新连接上执行


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

使用实例变量存储连接可能会有所帮助。大概是这样的:

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

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

如果您将所有数据库连接都保存在
数据库中,那就太好了。yml

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

other_envs:
.....
然后创建一个类

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

在这里查看我的博客

您可以在块内执行一些查询。首先,定义一些扩展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

在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
用法(假设您的
数据库.yml
中有另一个\u db:部分):


我使用取自Heroku的
数据库\u 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
e、 g:


如果您想连接到PostgresSQL,可以使用pgRubyGem&在块中添加以下代码

postgres = PG.connect :host => <host_name>, :port => <port>, :dbname => <database_name>, :user => <user>, :password => <password>
    tables = postgres.exec(query)

    tables.num_tuples.times do |i|
      print tables[i]
    end
db = Mysql2::Client.new ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(<database_url>).to_hash

    data = db.query(<<-SQL)
      select * from students
    SQL

    print data
postgres=PG.connect:host=>,:port=>,:dbname=>,:user=>,:password=>
tables=postgres.exec(查询)
tables.num_tuples.times do|i|
打印表格[i]
结束
要在块内连接到mysql db,请使用mysql2 ruby gem&在块内添加以下代码

postgres = PG.connect :host => <host_name>, :port => <port>, :dbname => <database_name>, :user => <user>, :password => <password>
    tables = postgres.exec(query)

    tables.num_tuples.times do |i|
      print tables[i]
    end
db = Mysql2::Client.new ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(<database_url>).to_hash

    data = db.query(<<-SQL)
      select * from students
    SQL

    print data
db=Mysql2::Client.new ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new()。到\u散列

data=db.query(Tryactive\u record\u slavegem:


这里的重要区别在于,连接是在所有普通对象的基类以外的对象上进行的,因此可以不使用与普通对象的连接。这也可以将配置保持在一个公共位置,并且我认为保持备用数据库连接打开,这对性能来说可能是一件好事mance,取决于您的使用条件。这段代码很好。您考虑过将其作为gem发布吗?@sufleR,不,我没有。也许这是值得的。@NoobieCorrect,这段代码不是线程安全的。更改ActiveRecord::Base connection会影响所有线程。您需要创建一个新的
ActiveRecord::ConnectionAdapters::ConnectionPool
f或者附加数据库,然后您可以使用连接块将代码包装到
my\u conn\u池中。
db = Mysql2::Client.new ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(<database_url>).to_hash

    data = db.query(<<-SQL)
      select * from students
    SQL

    print data