rake db:test:prepare

I'm having fun with a legacy DB (SQL Server), and in the process found
some code in rails/lib/tasks/databases.rake which feels wrong.

0) Errors which occur during this phase of a rake:test or rake:spec
tend to be ignored, although they are logically fatal. In the best
case, this means that the stack trace when an error finally does
manage to stop the process is worthless. Best case.

1) Prepare's strategy is to dump the current schema, blow away the
test db, and then rebuild the test schema from the dump. This strikes
me as dangerous in the event that someone has mucked with the db
outside of a migration--that is, made a change that won't get
reflected in source control. Wouldn't it be safer to just blow away
the test db & do the migrations to rebuild?

2) db:structure:dump for sqlserver requires the scptxfr executable,
which is part of the SQLServer package--not the client. While it is
likely that developers can get access to this file (and its supporting
files), there is no a priori reason to believe that a developer is
going to have access to this expensive bit of software. More
generally, should we not restrict dependencies to client code? (The
scptxfr script went away with SQLServer 2005, so this particular code
is also aging.)

3) Several of the tasks in the db namespace have code of the form
case abcs[blah]["adapter"]
  when "mysql", "oci", "oracle"
...
  when "postgresql"
...
  when "sqlserver"
...

...
end

This is generally considered bad practice ("hypnotic" coding). It is
not extensible, and it breaks the model of separating out code for the
commercial databases. Does rake support calls to computed tasks?

I'm having fun with a legacy DB (SQL Server), and in the process found
some code in rails/lib/tasks/databases.rake which feels wrong.

0) Errors which occur during this phase of a rake:test or rake:spec
tend to be ignored, although they are logically fatal. In the best
case, this means that the stack trace when an error finally does
manage to stop the process is worthless. Best case.

Yeah, I've actually been bitten by this in the past, please do
investigate a patch to make these errors get caught and reported in a
useful manner.

1) Prepare's strategy is to dump the current schema, blow away the
test db, and then rebuild the test schema from the dump. This strikes
me as dangerous in the event that someone has mucked with the db
outside of a migration--that is, made a change that won't get
reflected in source control. Wouldn't it be safer to just blow away
the test db & do the migrations to rebuild?

This has been discussed in the past, cloning development (by importing
schema.rb) is the preferred way of doing this. The short reasons are:

* Most migrations in a large application are for munging production data
* it takes far too
* and there's no guarantee that it will continue to work (referencing
old models etc)

The question of when the schema gets dumped is an open one. The
reason it's done in that rake task is that prior to migrations the way
you made changes to your database was to issue DDL directly against
the dev db, and you needed to have your tests dump the database if
they were to have any chance of working.

Now we could *probably* just dump schema.rb after running a migration,
and load it before test runs. This will reduce the changes of it
containing 'bogus' information, without making you run all 400
migrations for every test run.

2) db:structure:dump for sqlserver requires the scptxfr executable,
which is part of the SQLServer package--not the client. While it is
likely that developers can get access to this file (and its supporting
files), there is no a priori reason to believe that a developer is
going to have access to this expensive bit of software. More
generally, should we not restrict dependencies to client code? (The
scptxfr script went away with SQLServer 2005, so this particular code
is also aging.)

3) Several of the tasks in the db namespace have code of the form
case abcs[blah]["adapter"]
  when "mysql", "oci", "oracle"
...
  when "postgresql"
...
  when "sqlserver"
...

...
end

This is generally considered bad practice ("hypnotic" coding). It is
not extensible, and it breaks the model of separating out code for the
commercial databases. Does rake support calls to computed tasks?

Even if rake doesn't support this we could push that behaviour into
the adapters. Something along the lines of

task db:structure:dump do
  current_adapter.dump!(any, arguments, needed)
end

Again, if you feel like working on this, we'd be happy to help you get
a patch ready to apply.

How timely. I've been working on just this stuff this week. I'm about to dive into patching db:test:prepare so all it does it load the schema.rb instead of dumping it from the dev db every time. That should "just work" ok, but if you want to be confident that schema.rb reflects the state of the dev db, you need to know that migrations have been run correctly. I'm working on a plugin that helps detect when you need to run migrations, even detecting when someone may have modified an old migration (by saving a snapshot of SHA1 hashes of all migrations files). The two changes should play well together.

For an alternative see my article at
http://pivots.pivotallabs.com/users/alex/blog/articles/305-collapsing-migrations

If you make it part of your process to regularly collapse migrations
(like after every deploy), you avoid both of the problems mentioned
above (referencing old class definitions and taking a long time) but
you also avoid the problems with relying on schema.rb, namely :

* your development and test environments will be using the same
technique (migrations) for creating/altering the DB
* your migrations will be exercised by developers and test builds
before being deployed
* you won't get burned by forgetting to export and check in schema.rb
after adding a migration

Anyway, I'm not trying to change anyone's mind here, but this
technique has worked really well for us on several projects.

Cheers -

- Alex