web-dev-qa-db-fra.com

Connexion Rails 3.1 avec plusieurs bases de données

Chez ShowNearby, nous avons effectué une très grande migration vers RoR 3.1 depuis PHP et nous sommes confrontés à plusieurs problèmes que certains d'entre vous ont peut-être déjà résolus.

Nous avons de grandes quantités de données et nous avons décidé de séparer notre base de données en plusieurs bases de données que nous pouvons gérer séparément. Par exemple, nos comptes, lieux, journaux et autres sont divisés en plusieurs bases de données

Nous devons obtenir des migrations, des fixtures, des modèles, pour bien jouer, et jusqu'à présent, cela a été assez compliqué. Certaines de nos exigences pour qu'une solution soit acceptable:

  • un modèle doit concerner une table dans l'une des bases de données.
  • rake db: drop - devrait supprimer toute la base de données env que nous spécifions dans database.yml
  • rake db: create - devrait créer toutes les bases de données env que nous spécifions dans database.yml
  • rake db: migrate - devrait exécuter des migrations vers les différentes bases de données
  • rake db: test - devrait saisir les appareils et les déposer dans les différentes bases de données et l'unité de test/fonction/etc

Nous envisageons de définir des projets Rails pour chaque base de données et de les connecter à ActiveResource, mais nous pensons que ce n'est pas très efficace. Avez-vous déjà rencontré un problème similaire auparavant?

Merci beaucoup!!

77
Fer Martin

Pour répondre à Wukerplank, vous pouvez également mettre les détails de connexion dans database.yml comme d'habitude avec un nom comme ceci:

log_database_production:
  adapter: mysql
  Host: other_Host
  username: logmein
  password: supersecret
  database: logs

Puis dans votre modèle spécial:

class AccessLog < ActiveRecord::Base
  establish_connection "log_database_#{Rails.env}".to_sym
end

Pour éviter que ces informations gênantes ne figurent dans votre code d'application.

Edit: Si vous souhaitez réutiliser cette connexion dans plusieurs modèles, vous devez créer une nouvelle classe abstraite et en hériter, car les connexions sont étroitement couplées aux classes (comme expliqué ici , ici et ici ), et de nouvelles connexions seront créées pour chaque classe.

Si tel est le cas, configurez les choses comme suit:

class LogDatabase < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "log_database_#{Rails.env}".to_sym
end

class AccessLog < LogDatabase
end

class CheckoutLog < LogDatabase
end
142
Unixmonkey

La connexion à différentes bases de données est assez simple:

# model in the "default" database from database.yml
class Person < ActiveRecord::Base

  # ... your stuff here

end

# model in a different database
class Place < ActiveRecord::Base

  establish_connection (
    :adapter  => "mysql",
    :Host     => "other_Host",
    :username => "username",
    :password => "password",
    :database => "other_db"
  )

end

Je me méfierais de mettre en place plusieurs projets Rails car vous ajouterez beaucoup de frais généraux à la récupération de données pour vos contrôleurs, ce qui pourrait ralentir les choses.

Quant à vos questions sur les migrations, les appareils, les modèles, etc.: je ne pense pas qu'il y aura un moyen facile, alors veuillez poster des questions séparées et être aussi précis que possible.

La consolidation des bases de données en un seul n'est pas une option? Cela vous rendrait la vie beaucoup plus facile!

18
Wukerplank

Trouvé un excellent article qui indiquera aux autres la bonne façon de faire cette vérification http://blog.bitmelt.com/2008/10/connecting-to-multiple-database-in-Ruby.html =

Configurez quelque chose comme ceci:

database.yml (fichier de configuration db)

support_development:
    adapter: blah
    database: blah
    username: blah
    password: blah

support_base.rb (un fichier modèle)

class SupportBase < ActiveRecord::Base
    self.abstract_class = true #important!
    establish_connection("support_development")
end

tst_test.rb (un fichier modèle)

class TstTest < SupportBase 
    #SupportBase not ActiveRecord is important!

    self.table_name = 'tst_test'

    def self.get_test_name(id)
        if id = nil
            return ''
        else
            query = "select tst_name from tst_test where tst_id = \'#{id}\'"
            tst = connection.select_all(query) #select_all is important!
            return tst[0].fetch('tst_name')
        end
    end
end

PS, cela ne couvre vraiment pas les migrations, je ne pense pas que vous puissiez faire des migrations sur plus d'une base de données avec râteau (même si je ne suis pas sûr que ce soit difficile 'ne peut pas faire', cela peut être possible). C'était juste un excellent moyen de se connecter et d'interroger d'autres bases de données que vous ne contrôlez pas.

11
TwoByteHero

Vous pouvez également vouloir ajouter l'environnement Rails, afin que vos bases de données de développement et de test ne soient pas les mêmes.

establish_connection "legacy_#{Rails.env}"
5
Kris

article suivant suggère de définir de nouvelles tâches Rake pour réaliser des migrations sur plusieurs bases de données. Chaque tâche établit sa propre connexion, puis exécute la migration avec cette connexion et le dossier de base de données spécifique.

Il définit également un db:migrate qui appelle les deux autres tâches.

Y compris ici au cas où le lien deviendrait indisponible:

desc "Migrate the database through scripts in db/migrate directory."

namespace :db do
  task :migrate do
    Rake::Task["db:migrate_db1"].invoke
    Rake::Task["db:migrate_db2"].invoke
  end

  task :migrate_db1 do
    ActiveRecord::Base.establish_connection DB1_CONF
    ActiveRecord::Migrator.migrate("db/migrate/db1/")
  end

  task :migrate_db2 do
    ActiveRecord::Base.establish_connection DB2_CONF
    ActiveRecord::Migrator.migrate("db/migrate/db2/")
  end
end

Source: Ruby on Rails Se connecter à plusieurs bases de données et migrations

3
cweston

Hé, ce post est ancien mais j'ai trouvé une solution fonctionnant sur Rails 3.2 qui pourrait aider quelqu'un d'autre. https://stackoverflow.com/a/16542724/1447654 =

1
Rafael