We have a variety of applications, many built with Ruby on Rails, to support providing GFD (Great Freakign Data) to our clients. As software engineers responsible for building, maintaining, and improving those applications, we regularly need to change and update our different database structures. Rails ActiveRecord::Migration gives us the ability to handle these changes easily and consistently. Many of our migrations are simple and might look something like:
class AddNotesToPriceChecks < ActiveRecord::Migration
def change
add_column :price_checks, :notes, :string
end
end
As far as migrations go, there’s nothing too unusual here. As Rails developers, we’re all familiar with using the change method in our migrations to update our database schema. However, during a recent exploration of our codebase, I found a migration that looked a bit different from what I’m used to:
class RenameCategoryNamesToCategoryIdsInDownloads < ActiveRecord::Migration
def up
add_column :downloads, :category_ids, :text
rename_column :downloads, :category_names, :temporary_category_names
end
def down
rename_column :downloads, :temporary_category_names, :category_names
remove_column :downloads, :category_ids
end
end
def up and def down? What’s up with that?
What Goes Up Must Come Down
If you’re new to Rails, or have perhaps only worked with more modern versions, up and down might not be familiar. So what exactly do they do? The Rails guide best explains it:
You can also use the old style of migration using
up
anddown
methods instead of the change method. The up method should describe the transformation you’d like to make to your schema, and the down method of your migration should revert the transformations done by theup
method. In other words, the database schema should be unchanged if you do an up followed by a down. For example, if you create a table in the up method, you should drop it in the down method. It is wise to perform the transformations in precisely the reverse order they were made in the up method.
In other words, the changes in up are the forward change you want to make to your db, where the changes defined in down should be changes to revert back in time. When you run rails db:migrate, the up method is executed, whereas rails db:rollback executes the down method. Simply, up runs the migration, down rolls the migration back.
Change is (Usually) Good
But what about change? As I mentioned above, the change method is more commonly used. It’s newer to Rails and the primary way to write migrations. In most cases, change accomplishes alone what up and down do together. Using the example from above again:
class AddNotesToPriceChecks < ActiveRecord::Migration
def change
add_column :price_checks, :notes, :string
end
end
Is the same as:
class AddNotesToPriceChecks < ActiveRecord::Migration
def up
add_column :price_checks, :notes, :string
end
def down
remove_column :price_checks, :notes
end
end
For most migrations, ActiveRecord is smart enough to figure out the reverse of the migration defined in change. For example, if change calls add_index when running the migration, then it will know to call remove_index when rolling back. (See the Rails guide for a list of migration definitions supported by change).
The Classics Never Die
If change does both, why bother with up and down? In some cases, your migration may require manual changes outside of Rails conventions that change does not support and can’t automatically figure the inverse of. For example, to manage some of our tables, we have implemented a “soft delete” service:
class AddProductVersionIdToAdvertisements < ActiveRecord::Migration
def up
SoftDelete::DropAllViews.drop_advertisements_view
add_column :advertisements, :product_version_id, :integer
add_index :advertisements, :product_version_id
SoftDelete::AddAllViews.add_advertisements_view
end
def down
SoftDelete::DropAllViews.drop_advertisements_view
remove_index :advertisements, :product_version_id
remove_column :advertisements, :product_version_id, :integer
SoftDelete::AddAllViews.add_advertisements_view
end
end
If this migration was simply going to add a new column to our Advertisements Table, change would be enough here. However, in this migration we call our soft delete service that executes some SQL that change doesn’t know how to handle if the migration should be reversed. So we use up and down to specify what needs to be executed in the forward change and reverse for this migration.
In most cases (hopefully), your database schema updates will be straightforward enough that change will be the appropriate method to use in your migrations. However, for those times when your migration has some more complex logic, it’s always handy to have up and down in your back pocket!
For more than 16 years, gap intelligence has served manufacturers and sellers by providing world-class services monitoring, reporting, and analyzing the 4Ps: prices, promotions, placements, and products. Email us at info@gapintelligence.com or call us at 619-574-1100 to learn more.