Hi --
I have a project where there are an arbitrary number of databases, all
of which have the same schema, but different data. In light of this,
I'm trying to generate sets of models on the fly (one set per database).
I need to be able to access several databases simultaneously without the
connections overwriting each other. The traditional method for
accessing multiple databases is to subclass ActiveRecord::Base as an
abstract class for making the connection, then subclassing the abstract
class to make the models. This isn't scalable, however, as I would have
to manually create a new set of classes for each database.
I can generate classes on the fly and achieve the same effect as the
traditional method, but for some reason ActiveRecord won't pick up my
validations.
Below is my test code for both methods:
------------------------------
statically defined classes
------------------------------
require 'rubygems'
require 'active_record'
class DbBase < ActiveRecord::Base
self.abstract_class = true
end
class AudioFile < DbBase
validates_presence_of :name
end
DbBase.establish_connection(:adapter => 'sqlite3', :database =>
'test1.db')
a = AudioFile.new
puts a.valid? --> false
------------------------------
dynamically defined classes
------------------------------
require 'rubygems'
require 'active_record'
DbBase = Class.new(ActiveRecord::Base) do
self.abstract_class = true
end
AudioFile = Class.new(DbBase) do
validates_presence_of :name
end
DbBase.establish_connection(:adapter => 'sqlite3', :database =>
'test1.db')
a = AudioFile.new
puts a.valid?
------------------------------
Any ideas on how I can do this dynamic definition without ActiveRecord
ignoring my validations?
I think that what's happening is that when you do the AF =
Class.new(DbBase) version, the rhs gets evaluated before the
assignment (of course). That means that a bunch of inheritance
callback stuff gets executed with respect to an anonymous class. The
part I haven't found is why that matters, since the class then gets
bound to a constant... but it does appear to matter.
So -- and I present this more as a way to spot the problem, than a way
to solve it elegantly -- you can re-execute some inheritance callback
code, using the new class.
AudioFile = Class.new(ActiveRecord::Base)
ActiveRecord::Base.send(:inherited_with_inheritable_attributes,
AudioFile)
I'm still not sure exactly what makes the inheritance hooks care
whether the new subclass is anonymous or not. Nor do I know whether
re-executing that method is harmful... but it's ugly enough not to be
a long-term solution anyway
David