Rake tasks for run Rails engines migrations
I created a patch for run engine's migrations, it adds two Rake tasks:
- db:migrate:engines
- db:migrate:engines:down
The first one allows to run all the migrations stored in the db/migrate directory of each plugin.
It runs migrations in the same order Rails::Initializer register the plugins, this means if you force an order by environment.rb, it will be reflected on migrations order.
Example:
You have four plugins in your app: apple, bar, foo, pear.
1 # environment.rb 2 Rails::Initializer.run do |config| 3 config.plugins = [ :foo, :bar, :all ] 4 end
The task will run migrations in the following order: foo, bar, apple, pear.
It also add table structure declaration to your db/schema.rb (only if ActiveRecord::Base.schema_format == :ruby) and leave untouched your original version value.
This make totally independent app migrations from engine migrations.
Example:
1 db/migrate/20090224121645_create_birds.rb 2 3 vendor/plugins/foo/db/migrate/20080224121645_create_foos.rb 4 vendor/plugins/foo/db/migrate/20080224121646_create_bars.rb 5 6 $ rake db:migrate # => create birds (current tables: birds) 7 $ rake db:migrate:engines # => create foos and bars (current tables: birds, foos and bars) 8 $ rake db:migrate VERSION=0 # => delete birds (current tables: foos and bars) 9 $ rake db:migrate # => create birds, again (current tables: birds, foos and bars) 10 $ rake db:migrate:engines:down # => delete foos and bars (current tables: birds)
You can also specify if run migrations only from a specific engine:
1 $ rake db:migrate:engines ENGINE=foo # => run migrations from 'foo' engine only 2 $ rake db:migrate:engines:down ENGINE=foo # => run down migrations from 'foo' engine only 3 $ rake db:migrate:engines ENGINE=bar # => raise an exception if 'bar' engine is missing
This patch also supports mixed migrations versioning, this means you can use both timestamped and numeric migrations in your plugins.
Example:
1 db/migrate/20090224121645_create_birds.rb 2 3 vendor/plugins/bar/db/migrate/001_create_bars.rb 4 vendor/plugins/foo/db/migrate/20080224121645_create_foos.rb 5 6 $ rake db:migrate # => create birds (current tables: birds) 7 $ rake db:migrate:engines # => create from bar and foo (current tables: birds, bars and foos) 8 $ rake db:migrate:engines:down ENGINE=bar # => delete from bar (current tables: birds and foos)
You can also run migrations from engines first, then yours.
1 $ rake db:migrate:engines # => create from bar and foo (current tables: bars and foos) 2 $ rake db:migrate # => create birds (current tables: birds, bars and foos)
As you can see running migrations is an "engine atomic" operation, and it makes sense, because engines are pluggedin applications and you want to run all the migrations from a single engine, in order to make it full working.
Now imagine to have the 0.0.1 version of a plugin called 'foo' with the following migrations:
1 vendor/plugins/foo/db/migrate/20080224121645_create_foos.rb 2 vendor/plugins/foo/db/migrate/20080224121646_create_bars.rb
Your run your migrations, alongside with yours, so you have birds, foos and bars tables.
When the authors will release the 0.0.2, adding a third migration, if you execute db:migrate:engines, only the last migration will be ran, instead of the full suite.
And of course this is a bless if you want to keep up-to-date your plugins.
I created a Lighthouse ticket for this patch, so if you appreciate it, please vote with a +1.
UPDATE 2009-02-28: I completely rewrote the patch, changing its behavior, fixing stuff and adding a version column to schema_migrations.
Two important changes are about db:migrate and test tasks: they both automatically check/run migrations from plugins. This means test suite will be halted if there are pending migrations from plugins.
I also added a lot of new rake tasks (also for migrating from old Rails versions), and a script for rename a plugin.
For a full review, please visit the Lighthouse ticket.
UPDATE 2009-02-28 (2): I extracted the patch into a plugin: plugin_migrations.
advertising





Posted by James Adam on 2009-02-24 23:03:48 UTC (permalink)
It's great that you're focussing on bringing more engines features to Rails!
I'm slightly concerned about your notions of 'engine atomic', however. If I follow your example, engines can only ever be migrated completely up from scratch, or completely down from scratch. So, there's no way of telling what 'version' each engine has been migrated to, right? Or indeed, there's no way (other than examining the state of schema.rb exhaustively) of figuring out if a particular engine has been migrated. Is this correct?
Posted by Luca Guidi on 2009-02-25 08:22:06 UTC (permalink)
"Engine atomic" == there is no way to partially run engines migrations.
I don't think make sense to do this. An engine is a tiny app, plugged into your, it's something finished and complete, why partially run migrations from it?
Maybe I'm wrong, but for now I didn't figured to add this feature.
Talking about schema.rb there is no way, for now, to know which engines has been migrated. Maybe there is a way to do this.. :)
Posted by James Adam on 2009-02-25 10:46:20 UTC (permalink)
One of the big 'wins' with engines is being able to share updates and bug fixes across a bunch of applications.
This implies that engine plugins will be updated over the lifecycle of an application, and these updates should be able to include modifications to the database. It should also be possible to 'roll back' such updates, so the application is restored to its pre-update state.
I've spent a lot of time considering this :) I'll keep an eye on the ticket, and post more feedback there.