I had a crazy idea today based off a reader’s question[1].
Why are rake db:migrate and rake db:test:prepare two different tasks? Why can’t we have rake db:migrate migrate both the development and the test database at the same time? So many noobs (I’ll include myself in that basket too) get tripped up on this. How many times have you ran into it?
From what I can see, there is no reason at all why the development and test databases should be different. What would you think about having these as one task in Rails 3.0.1 or Rails 3.1, with obviously a deprecation warning for rake db:test:prepare or something?
I had a crazy idea today based off a reader's question[1].
Why are rake db:migrate and rake db:test:prepare two different tasks? Why
can't we have rake db:migrate migrate both the development and the test
database at the same time? So many noobs (I'll include myself in that basket
too) get tripped up on this. How many times have you ran into it?
From what I can see, there is no reason at all why the development and test
databases should be different. What would you think about having these as
one task in Rails 3.0.1 or Rails 3.1, with obviously a deprecation warning
for rake db:test:prepare or something?
Either that or dropping/loading the schema every time you require
"test_helper" (or equivalent), but definitely +1
One could take that idea a step further. Since many popular databases
don't support transactional DDL, it's not hard to write a bad
migration which fails and leaves the database stuck between
migrations, requiring manual cleanup. If we did as you suggest, we
could try to apply the migration first to the test database and only
if it succeeded, try to apply it to the development database. If it
failed, blowing away and recreating the test database would almost
certainly be less painful than manually cleaning up development.
I love this idea of keeping the test database as a backup and rolling back to it. I can completely understand why development and test are two separate databases and this would solidify that even further.
However, I can see a catch. If the test database is running then wouldn’t the data be wiped? Perhaps you would require this data for the development environment and if it’s gone, how are you going to get it back?
Luckily there’s also a way around this. Any important development data should be easily recoverable by running rake db:seed, because you’ve got your important data in db/seeds.rb, right?
This dual-migration should only happen if you’re in the development environment. If you’re in another environment such as staging it should only run it for the current environment.
Such as rake db:migrate:all? I like this idea too.
IMHO rake db:migrate:local (simply means development and test) is a better name. rake db:migrate:all gives an impression that it will run migrations for all environments.
You do not need an extra task to run migrations in dev and test.
Because the test database is loaded straight from db/schema.rb.
The flow is: you run db:migrate in the environment you want, say
"development". That dumps db/schema.rb as a side-effect, and the test
tasks load that file. They do not use migrations.
Some test tools such as Cucumber (and I’m sure I’ve seen it in RSpec but I cannot reproduce it right now) do not run the migrations before they run the tests. I think Rails should automatically do it so that when you run the tests the database is already setup. Why run it every time when you should only run it once? This would speed up the execution of the tests.
Bingo. That’s all rake db:test:prepare does: loads the schema into the test database. Whereas rake db:test:clone clones the structure+data from the development database to the test database.
When the test tasks warn that there are pending migrations they are not
saying that you need to run migrations on the test schema. They are
saying that db/schema.rb is outdated. And halt because normally
that's not good.
Now, from within the "test" environment you do not have information to
update db/schema.rb automatically.
The task to fix that already exists, it is db:migrate.
There may be valid reasons to not have your database on the most recent migration. It would be difficult for rails to know when it should go to the newest version and when it should stay at a particular one.
Some test tools such as Cucumber (and I'm sure I've seen it in RSpec but I
cannot reproduce it right now) do not run the migrations before they run the
tests. I think Rails should automatically do it so that when you run the
tests the database is already setup. Why run it every time when you should
only run it once? This would speed up the execution of the tests.
What happens is that rails', cucumber's and rspec's rake tasks run
db:test:prepare before. But if you run a single test, like "ruby
test/unit/model_test.rb", then the test database isn't loaded.
Maybe a simple solution for all this is providing a
"rails/test/reset_database" that, when required, drops the database
and requires Rails.root.join("db/schema"). That way we can include
that in rails/test_help and everytime the file is loaded, whether from
rake or an isolated test case being run, the database is up-to-date.