Skip to content

Instantly share code, notes, and snippets.

@mltsy
Created May 29, 2012 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mltsy/2830261 to your computer and use it in GitHub Desktop.
Save mltsy/2830261 to your computer and use it in GitHub Desktop.
2012/05/29 | Things I've learned about DataMapper Migrations

Things I discovered while trying to write a DM migration

So, the first Rails project I ever worked on was in DataMapper. I loved it - but I never learned how to use migrations. People say DataMapper is so awesome because you don't need them most of the time (which is so true), but they usually fail to address the question "what about when you do need them?" For instance, when you need to alter a table, or remove a column, etc. Fortunately, there are people who have thought about, and solved, this problem for us, they just haven't had the time, apparently, to document the solution for us very well.

Installing dm-migrations was a piece of cake: just add gem 'dm-migrations' to the Gemfile.

Using it, I ran into a few issues - partly as a result of my never having used ActiveRecord migrations in the first place, and partly because of a lack of conventions, or documentation for DataMapper migrations. So here are a few things I learned while trying to figure out how to write my first migration. Attached, you can see an actual sample migration file, and here are some pointers that answer several questions I had while writing it:

  • The filename doesn’t matter - call it whatever makes sense to you.

  • The file should be placed in the db/migrate directory of your application.

  • The name of the migration must be unique - that's how DataMapper knows which migrations you have deployed.

  • The number only signifies what order they will be run in. All the 1's will run before all the 2's etc. (they don't have to be unique)

  • You can use your updated models in the migration script to perform data manipulation, etc., as long as you don't use them until after you've called the necessary database updates so the database structure matches your model structure. In ActiveRecord, you have to run “reset_column_information”, but in DataMapper, the model structure is all based on the model definition in the code, so as long as your database supports everything the model is trying to do, "Bob's your uncle".

  • It is recommended (by dkubb and others) to use migrations short-term and only keep them in your repo until you know you don't need to roll back (a couple updates later). Auto-upgrade can always be used to build a new database structure from scratch for new environments, etc.

  • The use-case for keeping migrations around long-term is if there are customers or people using many different versions of your software, which you want to allow them to upgrade from v5 to v7 without pulling down and running through every update in between. (Note: in THAT case, you should NOT call model methods to perform data manipulation in your migration scripts, because the model definitions might change significantly enough in v.7 to invalidate the model expectations of an old migration, written circa v.5.

  • The db:migrate rake task is included in dm-rails, and to use it, you can't have the ActiveRecord task included, so be sure your config/application.rb file doesn't require 'rails/all' but only the ones you need from the DM rails 3 template. Specifically, 'dm-rails/railtie' which includes the DM db:migrate task. (And any others your application depends on)

  • Finally, a note about mixing auto-upgrade with migrations. This is perfectly normal, since you only need migrations to perform destructive changes. However, there's a small caveat: when there are no migrations present (in db/migrate), calling DM's rake db:migrate will perform the autoupgrade task, but if there are migration files, it will call migrate:up (and not perform an autoupgrade). Therefore, if you make an update to your models that you are expecting autoupgrade to catch, you need to either remove all migrations from the migration directory so DataMapper will autoupgrade for you, or explicitly run db:autoupgrade, after db:migrate is done. If you're using capistrano, and you happen to make a couple of updates in a row before deploying (or have to merge a couple together before deploying) where one uses a migration, and the other adds a field (which you may expect autoupgrade to catch) you will actually have to add a migration for that field as well, unless you deploy the two commits separately (deleting the migration file in between). The other option, of course, is to run rake db:autoupgrade manually, or modify your capistrano tasks to do both (first migrate:up then autoupgrade just in case).

# Here I used a date-stamp plus a counter (01) for the number, which I think is... an okay convention
# For the name, I use the ActiveRecord convention, plus a date-stamp, to ensure it's unique
migration 2012041201, :remove_primary_cat_id_from_businesses_20120412 do
up do
modify_table :businesses do
drop_column :primary_cat_id
end
end
# I didn't bother to write a "rollback";
# since it's actually destroying all the data, there's no turning back now!
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment