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
EDIT: last line of ‘dynamically defined classes’ code should read
puts a.valid? --> true
Your problem domain is not anything like the “usual” way that you
describe. In the usual way, (with the subclassing of AR::Base, the
different tables represent different models but in your case, you have
the same models across separate dbs.
I would approach this like this…
class AudioFile < ActiveRecord::Base
abstract_class = true
all AudoFile code validation code goes here…
end
[:db1, :db2, :db3].each do |db|
Class.new(“AudioFile#{db}”) do
establish_connection db
end
end
Not an answer to your question, but maybe reducing it will pinpoint
the issue.
David
–
Upcoming Rails training from David A. Black and Ruby Power and Light:
ADVANCING WITH RAILS, April 14-17 2008, New York City
CORE RAILS, June 24-27 2008, London (Skills Matter)
See http://www.rubypal.com for details. Berlin dates coming soon!
AudioFile = Class.new(DbBase) do
validates_presence_of :name
end
Try changing that to:
(AudioFile = Class.new(DbBase)).class_eval do
validates_presence_of :name
end
David
–
Upcoming Rails training from David A. Black and Ruby Power and Light:
ADVANCING WITH RAILS, April 14-17 2008, New York City
CORE RAILS, June 24-27 2008, London (Skills Matter)
See http://www.rubypal.com for details. Berlin dates coming soon!
I did find a solution. When I was using a single database, I had all of
my models wrapped up in a module so I could have cleaner module-level
methods for connecting to the db, getting/setting flags in the db, etc.
I turns out that if you make a copy of the module and change the module
and db name, you get a whole new isolated connection. So I wrote a
method to copy the module and change the name. Seems to work well. If
you need more info, let me know. Thanks to all who helped out with
this.
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.
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
–
Upcoming Rails training from David A. Black and Ruby Power and Light:
ADVANCING WITH RAILS, April 14-17 2008, New York City
CORE RAILS, June 24-27 2008, London (Skills Matter)
See http://www.rubypal.com for details. Berlin dates coming soon!
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.