Múltiples bases de datos en Rails


Se Puede hacer esto? En una sola aplicación, que gestiona muchos proyectos con SQLite. Lo que quiero es tener una base de datos diferente para cada proyecto que gestione mi aplicación.. así que múltiples copias de una base de datos idéntica estructura, pero con diferentes datos en ellos. Voy a elegir qué copia utilizar en base params en el URI.

Esto se hace para 1. seguridad.. Soy un novato en este tipo de programación y no quiero que suceda que por alguna razón mientras trabajo en un Proyecto otro se corrompe.. 2. fácil copia de seguridad y archivo de proyectos antiguos

Author: Simone Carletti, 2009-12-01

7 answers

Rails por defecto no está diseñado para una arquitectura de bases de datos múltiples y, en la mayoría de los casos, no tiene ningún sentido. Pero sí, puede utilizar diferentes bases de datos y conexiones.

Aquí hay algunas referencias:

 39
Author: Simone Carletti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-02 11:50:57

Si es capaz de controlar y configurar cada instancia de Rails, y puede permitirse el lujo de desperdiciar recursos debido a que están en espera, ahórrese algunos problemas y simplemente cambie la base de datos.yml para modificar la conexión de base de datos utilizada en cada instancia. Si le preocupa el rendimiento, este enfoque no lo logrará.

Para los modelos enlazados a una sola tabla única en una sola base de datos, puede llamar a establish_connection dentro del modelo:

establish_connection "database_name_#{RAILS_ENV}"

Como se describe aquí: http://apidock.com/rails/ActiveRecord/Base/establish_connection/class

Tendrá algunos modelos usando tablas de una base de datos y otros modelos diferentes usando tablas de otras bases de datos.

Si tiene tablas idénticas, comunes en diferentes bases de datos y compartidas por un solo modelo, ActiveRecord no lo ayudará. En el 2009 lo necesité en un proyecto en el que estaba trabajando, usando Rails 2.3.8. Tenía una base de datos para cada cliente, y nombré las bases de datos con sus identificaciones. Así que creé un método para cambiar la conexión dentro de ApplicationController:

def change_database database_id = params[:company_id]
    return if database_id.blank?

    configuration = ActiveRecord::Base.connection.instance_eval { @config }.clone
    configuration[:database] = "database_name_#{database_id}_#{RAILS_ENV}"

    MultipleDatabaseModel.establish_connection configuration
end

Y agregó ese método como un before_filter a todos los controladores:

before_filter :change_database

Así que para cada acción de cada controlador, cuando params[:company_id] se define y establece, cambiará la base de datos a la correcta.

Para manejar las migraciones extendí ActiveRecord:: Migration, con un método que busca todos los clientes e itera un bloque con cada ID:

class ActiveRecord::Migration
    def self.using_databases *args
        configuration = ActiveRecord::Base.connection.instance_eval { @config }
        former_database = configuration[:database]

        companies = args.blank? ? Company.all : Company.find(args)

        companies.each do |company|
            configuration[:database] = "database_name_#{company[:id]}_#{RAILS_ENV}"
            ActiveRecord::Base.establish_connection configuration

            yield self
        end

        configuration[:database] = former_database
        ActiveRecord::Base.establish_connection configuration
    end
end

Tenga en cuenta que por al hacer esto, sería imposible realizar consultas dentro de la misma acción desde dos bases de datos diferentes. Puede llamar a change_database de nuevo, pero se volverá desagradable cuando intente usar métodos que ejecuten consultas, desde los objetos que ya no están vinculados a la base de datos correcta. Además, es obvio que no podrá unir tablas que pertenezcan a diferentes bases de datos.

Para manejar esto correctamente, ActiveRecord debe ampliarse considerablemente. Ya debería haber un plugin para ayudarle con este problema. Una investigación rápida me dio este:

DB-Charmer: http://kovyrin.github.com/db-charmer /

Estoy dispuesto a probarlo. Hazme saber qué funciona para ti.

 26
Author: adeandrade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-04 08:35:38

Superé esto agregando esto a la parte superior de mis modelos usando la otra base de datos

class Customer < ActiveRecord::Base
  ENV["RAILS_ENV"] == "development" ? host = 'devhost' : host = 'prodhost'

  self.establish_connection(
      :adapter  => "mysql",
      :host     => "localhost",
      :username => "myuser",
      :password => "mypass",
      :database => "somedatabase"
    )
 12
Author: rdaniels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-25 17:24:39

También deberías echar un vistazo a este proyecto llamado DB Charmer: http://kovyrin.net/2009/11/03/db-charmer-activerecord-connection-magic-plugin /

DbCharmer es un plugin simple pero potente para ActiveRecord que hace algunas cosas:

  1. Le permite administrar fácilmente las conexiones de los modelos AR (métodoswitch_connection_to)
  2. Le permite cambiar las conexiones predeterminadas de los modelos AR a servidores/bases de datos separados
  3. le Permite elegir fácilmente donde su query should go (on_* familia de métodos)
  4. Le permite enviar automáticamente consultas de lectura a sus esclavos mientras que los maestros manejarían todas las actualizaciones.
  5. Añade múltiples migraciones de bases de datos a ActiveRecord
 4
Author: SquareCog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-02 12:08:51

Vale la pena señalar que en todas estas soluciones debe recordar cerrar las conexiones de base de datos personalizadas. se quedará sin conexiones y verá problemas de tiempo de espera de solicitud extraños de lo contrario.

Una solución fácil es clear_active_connections! en un after_filter en su controlador.

after_filter :close_custom_db_connection

def close_custom_db_connection
  MyModelWithACustomDBConnection.clear_active_connections!
end
 2
Author: Steven Soroka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-14 17:09:27

En su configuración/base de datos.yml hacer algo como esto

default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5

development:
  <<: *default
  database: mysite_development

test:
  <<: *default
  database: mysite_test

production:
  <<: *default
  host: 10.0.1.55
  database: mysite_production
  username: postgres_user
  password: <%= ENV['DATABASE_PASSWORD'] %>

db2_development:
  <<: *default
  database: db2_development

db2_test:
  <<: *default
  database: db2_test

db2_production:
  <<: *default
  host: 10.0.1.55
  database: db2_production
  username: postgres_user
  password: <%= ENV['DATABASE_PASSWORD'] %>

Luego en sus modelos puede hacer referencia a db2 con

class Customers < ActiveRecord::Base
  establish_connection "db2_#{Rails.env}".to_sym
end
 0
Author: rdaniels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-23 21:57:59

Lo que has descrito en la pregunta es multitenancia (bases de datos estructuradas de forma idéntica con diferentes datos en cada una). El Apartamento gem es ideal para esto.

Para la cuestión general de múltiples bases de datos en Rails: ActiveRecord soporta múltiples bases de datos, pero Rails no proporciona una forma de administrarlas. Recientemente creé la gema Multiverso para abordar esto.

 0
Author: Andrew Kane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-13 06:26:11