53 votes

Bases de données multiples dans Rails

Est-ce possible ? Dans une seule application, qui gère de nombreux projets avec SQLite. Ce que je veux, c'est avoir une base de données différente pour chaque projet que mon application gère donc plusieurs copies d'une base de données structurée de manière identique, mais contenant des données différentes. Je choisirai la copie à utiliser en fonction des paramètres de l'URI.

Ceci est fait pour 1. sécurité Je suis un novice dans ce genre de programmation et je ne veux pas qu'il arrive que pour une raison quelconque, alors que je travaille sur un projet, un autre soit corrompu 2. sauvegarde et archivage facile des anciens projets

0 votes

40voto

Simone Carletti Points 77653

Par défaut, Rails n'est pas conçu pour une architecture multi-bases de données et, dans la plupart des cas, cela n'a aucun sens. Mais oui, vous pouvez utiliser des bases de données et des connexions différentes.

Voici quelques références :

0 votes

Je n'aurais pas pu mieux dire. Les environnements facilitent également l'utilisation d'un système de base de données différent entre la production et le développement, par exemple. Je ne recommanderais pas de faire cela en pensant

0 votes

Je prévois de faire un choix similaire car je m'attends à ce que certaines tables de la base de données aient des centaines de millions d'enregistrements. La division de la base de données en instances distinctes par client me permettrait d'avoir un seul serveur d'applications avec plusieurs serveurs de bases de données.

0 votes

Vos deux derniers liens ne sont plus pertinents. Et le premier pourrait devenir obsolète avec une nouvelle version de rails. Veuillez mettre en ligne les morceaux de code concernés dans votre réponse.

28voto

adeandrade Points 363

Si vous êtes en mesure de contrôler et de configurer chaque instance de Rails, et que vous pouvez vous permettre de gaspiller des ressources parce qu'elles sont en standby, épargnez vous quelques soucis et changez simplement le database.yml pour modifier la connexion à la base de données utilisée sur chaque instance. Si vous êtes préoccupé par les performances, cette approche ne sera pas suffisante.

Pour les modèles liés à une seule table unique sur une seule base de données, vous pouvez appeler establish_connection à l'intérieur du modèle :

establish_connection "database_name_#{RAILS_ENV}"

Comme décrit ici : http://apidock.com/rails/ActiveRecord/Base/establish_connection/class

Vous aurez certains modèles utilisant des tables d'une base de données et d'autres modèles différents utilisant des tables d'autres bases de données.

Si vous avez des tables identiques, communes sur différentes bases de données, et partagées par un seul modèle, ActiveRecord ne vous aidera pas. En 2009, j'ai eu besoin de cela sur un projet sur lequel je travaillais, en utilisant Rails 2.3.8. J'avais une base de données pour chaque client, et j'ai nommé les bases de données avec leurs IDs. J'ai donc créé une méthode pour changer la connexion dans 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

Et j'ai ajouté cette méthode comme un avant_filtre à tous les contrôleurs :

before_filter :change_database

Ainsi, pour chaque action de chaque contrôleur, lorsque params[:company_id] est défini et activé, la base de données est modifiée pour devenir la bonne.

Pour gérer les migrations j'ai étendu ActiveRecord::Migration, avec une méthode qui cherche tous les clients et itère un bloc avec chaque 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

Notez qu'en procédant ainsi, il vous serait impossible d'effectuer des requêtes dans la même action à partir de deux bases de données différentes. Vous pouvez appeler change_database mais cela devient désagréable lorsque vous essayez d'utiliser des méthodes qui exécutent des requêtes, à partir des objets qui ne sont plus liés à la bonne base de données. De plus, il est évident que vous ne pourrez pas joindre des tables qui appartiennent à des bases de données différentes.

Pour gérer cela correctement, ActiveRecord devrait être considérablement étendu. Il devrait y avoir un plugin pour vous aider à résoudre ce problème. Une recherche rapide m'a donné celui-ci :

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

Je suis prêt à l'essayer. Faites-moi savoir ce qui fonctionne pour vous.

12voto

user3140648 Points 21

J'ai surmonté ce problème en ajoutant ceci au sommet de mes modèles en utilisant l'autre base de données.

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"
    )

4voto

SquareCog Points 12947

Vous devriez également consulter ce projet appelé DB Charmer : http://kovyrin.net/2009/11/03/db-charmer-activerecord-connection-magic-plugin/

DbCharmer est un plugin simple mais puissant pour ActiveRecord qui fait plusieurs choses :

  1. Permet de gérer facilement les connexions des modèles AR ( switch_connection_to méthode)
  2. Vous permet de changer les connexions par défaut des modèles AR vers des serveurs/bases de données distincts.
  3. Vous pouvez facilement choisir où votre requête doit aller ( on_* méthodes famille)
  4. Vous permet d'envoyer automatiquement des requêtes de lecture à vos esclaves tandis que les maîtres se chargeraient de toutes les mises à jour.
  5. Ajoute des migrations de bases de données multiples à ActiveRecord

1 votes

Le plugin a été tué par l'auteur, à partir du 02.01.2015, personne n'est intervenu pour le maintenir.

2voto

Steven Soroka Points 8446

Il convient de noter que dans toutes ces solutions, vous devez vous souvenir de fermer les connexions personnalisées aux bases de données. Vous pouvez consulter le site sera manquer de connexions et voir des problèmes bizarres de timeout de requête autrement.

Une solution simple consiste à utiliser clear_active_connections ! dans un after_filter de votre contrôleur.

after_filter :close_custom_db_connection

def close_custom_db_connection
  MyModelWithACustomDBConnection.clear_active_connections!
end

4 votes

Rails utilise un pool de connexion, il devrait empêcher la surutilisation de la limite de connexion.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X