Работа одновременно с несколькими базами данных в Ruby on Rails
Обычно на сайте, в веб-приложении работа ведется с моделями (таблицы) одной базы данных. Но иногда возникает необходимость работать с несколькими базами данных одновременно, например, централизованная обработка данных нескольких источников (баз данных), распределенная система, система с резервным хранением данных и т.п.
В базовой конфигурации приложения Ruby on Rails такой возможности не предусмотрено, но это не значит, что такой возможности нет. Мало того, существует несколько способов.
Суть заключается в использовании метода класса ActiveRecord::Base
establish_connection. Метод, как описано в документации, принимает хэш параметров соединения в качестве параметра. Но может быть так же передана и строка. Я использую MySQL, поэтому буду описывать параметры именно для работы с этой СУБД.
Способ 1
Как известно, конфигурация параметров соединения с базой данных (наименование базы данных, имя пользователя, пароль) хранится в файле config/database.yml
, в котором прописаны параметры для каждого вида окружения, стадии разработки приложения - разработка, тестирование и готовая версия.
Но, что самое интересное, можно добавить собственный раздел в файл config/database.yml
, например:
production: adapter: mysql2 encoding: utf8 reconnect: false database: dbname # основная база данных pool: 5 username: user password: pass1 socket: /var/run/mysqld/mysqld.sock # далее наш дополнительный раздел: another: adapter: mysql2 encoding: utf8 reconnect: false database: dbanother # другая база данных pool: 5 username: user2 password: pass12 socket: /var/run/mysqld/mysqld.sock
И, собственно, ради чего все эти операции? Вот тут начинается самое интересное. Мы можем определить модель, которая будет использовать наше соединение (с другой базой данных):
class Another < ActiveRecord::Base self.table_name = "mytable" # конечно, мы можем дополнительно # уточнить и имя таблицы self.establish_connection "another" # это наименование именно # нашего раздела, # описывающего соединение ... end
Теперь, работая с нашей моделью Another
, мы будем работать с базой данных dbanother
, в то время как остальные модели все так же будут продолжать использовать основную базу dbname
. Довольно удобно, не правда ли?
Для каждой стадии разработки мы точно так же можем создать собственный раздел нашей отдельной базы данных:
another_development: adapter: mysql2 ... another_test: adapter: mysql2 ... another_production: adapter: mysql2 ...
Изменим определение нашей модели:
class Another < ActiveRecord::Base ... # для использования различных версий # на различных стадиях разработки: self.establish_connection "another_#{Rails.env}" ... end
Способ 2
Возможно указание параметров соединения непосредственно в определении модели:
class Another < ActiveRecord::Base self.establish_connection( :adapter => 'mysql2', :host => 'localhost', :database => 'dbanother', :username => 'user2', :password => 'pass12' ) ... end
Способ 3
Возможно так же указание параметров соединения непосредственно перед использованием:
class Another < ActiveRecord::Base ... end ... # далее по коду, перед использованием Another.establish_connection( :adapter => 'mysql2', :host => 'localhost', :database => 'dbanother', :username => 'user2', :password => 'pass12' ) ... @query = Another.limit(10).all
Таким образом, как можно видеть во 2 и 3 способах, возможно использовать довольно мощный механизм работы с произвольными базами данных, а не только одновременно работать с несколькими базами данных.