Можно ли иметь несколько соединений ActiveRecord? - PullRequest
2 голосов
/ 30 апреля 2020

Я использую ActiveRecord вместе с Sqlite3 для некоторого анализа данных больших текстовых файлов, где есть несколько текстовых файлов, и каждый текстовый файл представляет «экземпляр» модели данных.

Для любого По данному текстовому файлу я анализирую его и в конечном итоге загружаю в совместимую с ActiveRecord базу данных Sqlite3. Например, каждая таблица может быть представлена ​​подклассом ApplicationRecord.

Итак, в результате я получаю набор баз данных (файлов) Sqlite3. Я хотел бы иметь возможность одновременно запускать запросы для нескольких «экземпляров», чтобы я мог сравнивать записи между «экземплярами».

В настоящее время я делаю что-то вроде этого:

  data_from_db1 = nil
  data_from_db2 = nil        

  ActiveRecord::Base.establish_connection(
    :adapter => "sqlite3",
    :database => db_1,
  )

  // code to extract data from the established connection
  // save data to data_from_db1 object

  ActiveRecord::Base.remove_connection

  ActiveRecord::Base.establish_connection(
    :adapter => "sqlite3",
    :database => db_2,
  )

  // code to extract data from the established connection
  // save data to data_from_db2 object

  ActiveRecord::Base.remove_connection

  // work with saved data_from_dbN objects 

Хотя это работает нормально, было бы намного лучше, если бы я мог как-то получить дескриптор для каждого соединения с базой данных, а затем просто направить свои запросы на указанные c базы данных.

Есть ли в любом случае, я могу сохранить несколько соединений активны и указать, какое из них использовать для данного запроса?

Это кажется невозможным, поскольку запросы привязаны к моделям, и я не вижу способа указать используемое соединение или даже как чтобы получить дескриптор для данного соединения.

Например, я могу делать запросы, такие как:

MyModel.where(....)

, но я думаю, что мне нужно было бы сделать что-то вроде:

MyModel.with_connection(foo).where(....)

Примечание: очень важно, чтобы я закрыл первое соединение, прежде чем установить sh следующее соединение, в противном случае, если я запрашиваю свойство модели, которую я извлек из первого соединения, вполне вероятно, что это свойство на самом деле является ActiveRecordRelation, и это свойство будет данными, возвращаемыми из текущего соединения, а не из предыдущего соединения. Закрытие соединения означает, что я вызову исключение, а не получу неправильные данные.

Небольшое обновление

Я знаю, что могу просто объединить все эти меньшие базы данных в одну большую базу данных, но я бы не стал сделайте это, так как есть много комбинаций баз данных, на которых я, возможно, захочу выполнить вычисления, а составная база данных будет просто огромной и излишней

Ответы [ 2 ]

2 голосов
/ 30 апреля 2020

Да, это возможно:

# app.rb
require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'activerecord'
  gem 'sqlite3'
end

require 'active_record'

class User < ActiveRecord::Base; end

User.connects_to database: {
  primary: { database: 'db1.sqlite', adapter: "sqlite3" },
  secondary: { database: 'db2.sqlite', adapter: "sqlite3" }
}


ActiveRecord::Base.connected_to(role: :primary) do
  User.connection.execute("CREATE TABLE IF NOT EXISTS `users` (name VARCHAR (255))")
  User.create name: 'Komodo'
end

ActiveRecord::Base.connected_to(role: :secondary) do
  User.connection.execute("CREATE TABLE IF NOT EXISTS `users` (name VARCHAR (255))")
  User.create name: 'Cendrawasih'
end

ActiveRecord::Base.connected_to(role: :primary) do
  puts 'Primary Table Records: ', User.all.inspect
end

ActiveRecord::Base.connected_to(role: :secondary) do
  puts 'Secondary Table Records: ', User.all.inspect
end

вывод:

$ ruby app.rb
Primary Table Records:
#<ActiveRecord::Relation [#<User name: "Komodo">]>
Secondary Table Records:
#<ActiveRecord::Relation [#<User name: "Cendrawasih">]>

пс:

Это очень интересный вопрос для меня, мне пришлось копать в тестовых примерах ActiveRecord, чтобы получить что-то вроде выше.

Спасибо elieencodes и Ryuta Kamizono за усилия по поддержке нескольких баз данных на активной записи. Я получаю имена из git blame в тестовых случаях. Вероятно, есть еще один участник.

2 голосов
/ 30 апреля 2020

Да, я делал это несколько раз, вам нужно будет сделать следующее

В вашем database.yml определите новые базы данных

production:
  username: 
  password: 
  host: 
  database: database

db2_production:
  username: 
  password: 
  host: 
  database: database2

Далее создайте новый файл Я обычно помещаю его в lib / customclasses / db2_database_record.rb

class SecondDatabaseRecord < ActiveRecord::Base
  self.abstract_class = true
  establish_connection :"db2_#{Rails.env}"
end

Убедитесь, что эти файлы включены в приложение rails в application.rb, например:

config.paths.add Rails.root.join('lib/customclasses').to_s, eager_load: true

Затем в модели то есть в этой базе данных обновите файл model.rb, чтобы посмотреть на новый пользовательский класс, который вы создали

class TableInDb2 < SecondDatabaseRecord
end

Очевидно, что имена классов должны быть чем-то значимым для вас. У меня есть одно приложение, которое общается с 3 различными базами данных, как это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...