Practical Tips for Rails Migrations

Migrations are a wonderful feature provided by the Rails framework. They provide an organized mechanism for building the database for an application, and are a distinct improvement over the random assortment of undocumented SQL scripts used by most projects.

The concepts behind migrations are so simple that you'd think that it would be difficult for anything to go awry.

You'd be wrong.

Here are some tips for getting the most effective use out of migrations in Rails.

  1. Down Methods: The down method of each migration should correctly back out the changes created by the up method. There is a tendency for developers to either skip the down method, or to implement the down method and then not test it effectively. Neither reason for an ineffective down method is acceptable.

    It is valid for some migrations to be non-reversible, but this should definitely not be the rule. Migrations that perform data conversions are often not reversible. Even if this is the case, a related group of migrations should be reversible whenever possible.

  2. Performance: Migrations are executed in development, test and production environments. To reduce the impact on customers, it is common for production applications to be brought down while database updates are occurring. A poorly performing migration can keep your production applications offline for an unacceptable amount of time. Remember that production databases often have much more data than development and test environments. Make sure that your migrations, particularly those that perform data conversions, run as efficiently as possible.

  3. DSL: Rails provides a nice Domain-Specific Language (DSL) for manipulating database tables in migrations. Use it.

    Only use SQL directly when the DSL cannot easily perform the task that is required. Using the DSL also has the added advantage of keeping your migrations database-agnostic, which will be beneficial if a change in database vendor is ever proclaimed by management.

  4. Sets: Sometimes new requirements are received that require a sweeping set of changes affecting multiple tables in a database. Often, the changes have no value individually, but must instead be implemented as a complete set in order to be useful. If the changes are relatively simple, they can all be incorporated into a single migration.

    On the other hand, more complex changes should probably be grouped into a set of migrations, with one migration for each table impacted. It's up to teams to develop their own convention for organizing migrations into sets, since there is no generally accepted convention for Rails migrations. One possible solution is to use the second term of a migration name to indicate a set, if applicable. In the example below, "release2" is used to indicate that the migrations are part of a set.

    046_release2_create_subscription.rb
    047_release2_modify_distributor.rb
    048_release2_modify_user.rb
    049_release2_remove_old_tables.rb

    The first term, of course, is either a sequential number or a timestamp, depending on how the development team wants to organize the migrations. Support for timestamps in migration names was added in Rails 2.0.

  5. Migration Sprawl: Sometimes the number of migrations mushrooms more than is needed. Imagine a situation in which numerous database changes are needed, and multiple people are working on the changes. Each person creates multiple migrations, some of them affecting the same tables. If all of the migrations are going to go into production at the same time, it may make sense for some consolidation to be done. For example, if there are six migrations affecting the same table, it may be more effective to have all of those changes done in one migration. The migrations will make more sense to users, and it will be easier for testers to verify that all of the changes have been done properly.



Comments

No comments yet. Be the first.



Leave a Comment

Comments are moderated and will not appear on the site until reviewed.

(not displayed)