Reputation: 47
I'm attempting to dynamically create a Class and assign one of several database connections to each Class.
I'm working with anywhere between two or three databases which change over time, therefore, I'm hesitant to store each connection string in a separate Class and inherit from it instead of ActiveRecord::Base.
The following throws an error "RuntimeError: Anonymous class is not allowed.", but I'm not sure how to work around it or if there are better 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
Upvotes: 2
Views: 1599
Reputation: 2860
You may set establish_connection
for model dynamically:
database.yml
development:
adapter: mysql
username: root
password:
database: example_development
oracle_development:
adapter: oracle
username: root
password:
database: example_oracle_development
And in any place of code you may change db connection of your model:
User.establish_connection "oracle_#{RAILS_ENV}".to_sym
Also you can create model classes dynamically:
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)
After that NewUser
class will be available to use.
This version works in both Rails 5.0 and 3.2.
Upvotes: 2
Reputation: 1767
Per ActiveRecord::ConnectionHandling#establish_connection
's source, you can't establish a connection from a class for which name
doesn't return a truthy value.
Now, you are assigning the class to a constant using const_set
, and that will give it a name. But you need to do that before you call 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
Also, do you really want Module.const_set(...)
? That will result in a class named Module::Foo
. Possibly you just want Object.const_set(...)
(which just gives Foo
)? Or even const_set(...)
, so you get ClassFactory::Foo
?
Upvotes: 4