My application spans 2 (or more) databases for some very specific
reasons… My models are working fine, even dynamically establishing
connections as needed at runtime, and spanning relationships across the
databases (which really impressed me). The problem is, I can’t seem to
force Units for these models (that use a secondary db) to load their
fixtures into and use the secondary database.
I tried applying this:
Project.establish_connection(:test_group)
(where :test_group is a database connection defined in database.yml)
at various locations within the test itself, and test_helper.rb… but
my unit is failing with this error:
ActiveRecord::StatementInvalid: Mysql::Error: Table
‘scoot_test.projects’ doesn’t exist: DELETE FROM projects
(and scoot_test is the ‘main’ database, but projects should be a table
in the ‘secondary’ database)
So, any advice on how I might be able to get this to work?
Rails stores the database tablename within the
corresponding ActiveRecord::base subclass. inside the
“connection_specification” class there is a hash which
contains information about which class is using which
db connection. and if there is no connection define
for a class it will go to its parent.
So what I understand, is that your have two databases,
and the class can finf its table? am I right.
if it is the case, it is because the class is using
the wrong connection, so the worng database.
SO I suggestion you to create two parents for your
databases. like db1 <activeRecords::base and db2
<activeRecords::base. all the table-class from db1
should inherited not directly form
activeRecords::base, but db1 and same for the
table-class from db2. when you connect dynamically to
your database, uses
db1.establish_connection(…) so all the table-class
used db1 will have the same db connection and the same
for db2.
actually, I’m using 2 db also. it works for me, so I
hope it will work for you.
Did you try to connect to 2 db within the same action?
if it is the case, I have an example code, that may
help, but not for all db, I’m using postgresql. so not
sure that it will work for all other databse.
If I understand you correctly, that’s kind of what I’m doing…
Project < ActiveRecord::Base
Project.establish_connection(:db2)
end
And all other models in db2 inherit from Project.
That works fine from the console… the problem is, when trying to write
unit tests, the fixtures for Project are being loaded into (well,
attempted at least) db1, but I can’t figure out why that would be.
I tried this:
Project < ActiveRecord::Base
Project.establish_connection(:db2)
if (RAILS_ENV == “test”) then
Project.establish_connection(:db2_test)
end
end
But it’s still trying to load things into db1_test… it almost seems
like ActiveRecord::Base.establish_connection is turned off during
testing…
It looks like the test code is just broken for multiple databases. The
only
database the code uses is the one set for Base, so your per-model
database
won’t work during testing.
It looked to be a non-trivial piece of work to make the test code work
with
multiple databases, so I moved on to something else.
In my case, it doesn’t matter too much, as I only have one very simple
model
in my second DB, and it’s real obvious in my app when it breaks!
I pressed on the wrong button:) what I want ot say is:
May be you should try:
Project < ActiveRecord::Base
if (RAILS_ENV == “test”) then
Project.establish_connection(:db2_test)
else
Project.establish_connection(:db2)
end
I think this is better, because the class will not be
assigned two times.
in my second DB, and it’s real obvious in my app when it breaks!
Did you try to connect to 2 db within the same action?
if (RAILS_ENV == “test”) then
Project.establish_connection(:db2_test)
Project.establish_connection(:db2)
Ok, I’ve been digging into ActiveRecord and fixtures.rb and it looks
like the reason this is broken is because fixtures don’t really look at
models to do their magic… they (by default) use the db connection of
ActiveRecord::Base.
I found a couple ways around this… The more complicated way (which
doesn’t seem to work anyway) was to create your own instance of
Fixtures:
class ProjectTest < Test::Unit::TestCase
fixtures :groups
Project.establish_connection(:test_group) @fix = Fixtures.new(Project.connection, “projects”,
File.dirname(FILE) + “/…/fixtures”) @fix.insert_fixtures
…
The problem is insert_fixtures isn’t really doing anything… I’m sure
there’s a way I just don’t completely understand the API.
I moved onto another method, which is to create my own custom rake tasks
that will load my custom fixtures into the 2nd database as needed. Then
I’ll insert it into the default test_units and test_functional tasks.
I’ll post the results as soon as I’m done.
Ok, I’ve been digging into ActiveRecord and fixtures.rb and it looks
like the reason this is broken is because fixtures don’t really look at
models to do their magic… they (by default) use the db connection of
ActiveRecord::Base.
I found a couple ways around this… The more complicated way (which
doesn’t seem to work anyway) was to create your own instance of
Fixtures:
class ProjectTest < Test::Unit::TestCase
fixtures :groups
Project.establish_connection(:test_group) @fix = Fixtures.new(Project.connection, “projects”,
File.dirname(FILE) + “/…/fixtures”) @fix.insert_fixtures
…
The problem is insert_fixtures isn’t really doing anything… I’m sure
there’s a way I just don’t completely understand the API.
I moved onto another method, which is to create my own custom rake tasks
that will load my custom fixtures into the 2nd database as needed. Then
I’ll insert it into the default test_units and test_functional tasks.
I’ll post the results as soon as I’m done.
m
Hello,
this seems to be working:
in the model:
if ENV[“RAILS_ENV”]==“test”
Person.establish_connection “db_test”
else
Person.establish_connection “db”
end
in the test - instead of “fixtures :people” something like this: