On the need for more robust Rails Migrations
Posted by Richard White Sat, 18 Feb 2006 02:06:00 GMT
One of the most frustrating parts of Rails Migrations is the fact that each migration is NOT transactional. Its possible that some query halfway through the migration could fail and leave you database schema in a “bad state”. After reading this blurb on RailsBestPractices on the RoR wiki I thought that it might be possible to wrap my migrations in a simple transaction, with the only caveat that it won’t work for MySQL:... Put a transaction around your migrations. That way, you know that you won’t be dumped out half-way through a migration, and have to disentangle whatever half-finished mess you end up with to try to run it again. The slight crimp to this is that MySQL doesn’t allow data definition commands (like CREATE TABLE, for instance) inside a transaction, and they cause an implicit commit. It’s still a good idea for data-only migrations, though.Unfortunately the following does not work
class TestTransaction
self.up
<strong> transaction do</strong>
create_table :widgets, :force => true do |t|
t.column :name, :string, :null => false
t.column :version, :string, :null => false
end
remove_column :widgets, :type
end
end
...
Because when I run rake migrate I get the following
rake aborted!
RuntimeError: ERROR
C25P02 Mcurrent transaction is aborted, commands ignored until
end of transaction block
Fpostgres.c L926 Rexec_simple_query: CREATE TABLE cars
("id" serial primary key, "make" character varying(255) NO
T NULL, "model" character varying(255) NOT NULL)
If anyone has any ideas drop me a line rrwhite AT gmail.com
Update: Thanks to Eric Pugh for pointing out that removing :force => true makes this work!
I came across this a few days ago. Basically, CREATE TABLE and friends aren’t transactional in MySQL (14.2.10.9. Implicit Transaction Commit and Rollback). You’re stuffed, basically. Probably the best you can do is stick any data modifications inside a transaction, after creating a table.
Or use PostgreSQL. ;-)
Dominic: Actually I am using PostgreSQL (notice the Fposgres.c in the error) and still couldn’t get it to work. I guess I should have been more clear about that.
I’ve had a plugin for quite some time now that does exactly this. It even handles the force => true problem for you but only issuing the delete command if the table exists. You can find the plugin here: http://www.redhillonrails.org/#transactional_migrations
I REALLY wish that this could become a plugin for rails. Some how…someone…anyone! :) -R