2017-03-16 1 views
1

ActiveRecord Je tente de créer dynamiquement une classe et affecter un de plusieurs connexions de base de données à chaque classe. Je travaille avec n'importe où entre deux ou trois bases de données qui changent au fil du temps, par conséquent, j'hésite à stocker chaque chaîne de connexion dans une classe distincte et en hériter au lieu de ActiveRecord :: Base.classe Ruby créer Dynamiquement avec connexion

Ce qui suit renvoie une erreur « RuntimeError: classe anonyme n'est pas autorisée. », Mais je ne suis pas sûr de savoir comment contourner ou s'il existe de meilleures alternatives.

class ClassFactory 
    def self.create_class(new_class, table, db_connection) 

     c = Class.new(ActiveRecord::Base) do 
     db = db_connection 
     self.table_name = table 
     establish_connection(:adapter => db.database_type, :host => db.host, :database => db.database, :username => db.username, :password => db.password).connection 
     end 

     Module.const_set new_class, c 
    end 
    end 

Répondre

0

Vous pouvez définir establish_connection pour le modèle dynamique:

database.yml

development: 
    adapter: mysql 
    username: root 
    password: 
    database: example_development 

oracle_development: 
    adapter: oracle 
    username: root 
    password: 
    database: example_oracle_development 

et en tout lieu de code que vous pouvez modifier la connexion db de votre modèle:

User.establish_connection "oracle_#{RAILS_ENV}".to_sym 

Vous pouvez également créer des classes de modèle de manière dynamique:

class ClassFactory 
    def self.create_class(new_class, table, connection_name) 

    Object.const_set(new_class, Class.new(ActiveRecord::Base) {}) 
    new_class.constantize.table_name = table 
    new_class.constantize.establish_connection(connection_name) 

    end 
end 

ClassFactory.create_class('NewUser', 'users', :development) 

Après cette classe NewUser sera disponible à utiliser.

Cette version fonctionne dans les deux Rails 5.0 et 3.2.

+1

par ma lecture de la source, cela ne devrait pas fonctionner; la toute première ligne de 'ActiveRecord :: ConnectionHandling # establish_connection' est' raise 'La classe anonyme n'est pas autorisée. " à moins que name', avant qu'il ne prenne un seul regard sur les paramètres que vous avez passés. Ai-je mal compris quelque chose? – philomory

+0

On dirait que le code ne fonctionnera que dans Rails 3.2 ou plus. [établir la source de connexion] (http://apidock.com/rails/v4.0.2/ActiveRecord/ConnectionAdapters/ConnectionHandler/establish_connection). Donnez-moi une seconde, je vais essayer de le faire fonctionner dans de nouveaux Rails. –

+0

Intéressant, je regardais 'ActiveRecord :: ConnectionHandling # establish_connection', pas' ActiveRecord :: ConnectionPool :: ConnectionHandler # establish_connection'. Je dois aimer les noms similaires pour les choses. – philomory

2

Par ActiveRecord::ConnectionHandling#establish_connection's source, vous ne pouvez pas établir une connexion à partir d'une classe pour laquelle name ne renvoie pas une valeur véridique.

Maintenant, vous assignez la classe à une constante en utilisant const_set, et qui lui donnera un nom. Mais vous devez le faire avant vous appelez establish_connection:

class ClassFactory 
    def self.create_class(new_class, table, db_connection) 
    c = Class.new(ActiveRecord::Base) do 
     db = db_connection 
     self.table_name = table 
    end 

    Module.const_set new_class, c 
    c.establish_connection(:adapter => db.database_type, :host => db.host, :database => db.database, :username => db.username, :password => db.password).connection 
    end 
end 

Aussi, voulez-vous vraiment Module.const_set(...)? Cela se traduira par une classe nommée Module::Foo. Peut-être que vous voulez juste Object.const_set(...) (qui donne juste Foo)? Ou même const_set(...), de sorte que vous obtenez ClassFactory::Foo?

+0

Merci, c'était utile. Tu as raison, je ne voulais pas ça. – martinmsf