How to not break your rails migration
When I first encountered migrations in rails I was amazed, to say the least. For the better part of last year, I’ve been writing Golang and Clojure both of which lack a powerful database client.
The ability to use application code in migrations is a very powerful feature and can be used in a myriad of ways. This feature becomes available because both your models and migrations are managed by ActiveRecord
and hence you can easily play around with your models which inherit from ActiveRecord
.
Let’s recall what a database migration is. It is just a commit over the state of the database. What that essentially means is that if for some reason we need to recreate our database state, we can rerun these commits(logs) and arrive at the expected state. We use it all the time, for example, while running tests.
This very property of recreating the database state through migrations can be jeopardized if our application code being used in migrations is invalid. Let us understand this through an example. In this case, we want to update all our Applications type to Service
.
class UpdateApplicationType < ActiveRecord::Migration[5.1]
def change
reversible do |dir|
dir.up do
Applications.all.each do |app|
app.update(type: 'Service')
end
end
end
end
end
The catch in this migration is, what happens when let’s say after a year you don’t really need that model and you would like to delete the code. That would break your database migration. You could go ahead and delete the migration but you are changing the history of how your database arrived at this state. Is there a better way to do it? Of course, there is. In such a case, we can redefine the class we need to use in migration code and we get the best of both worlds. Something along the lines of
class Application < ActiveRecord::Base
end
class UpdateApplicationType < ActiveRecord::Migration[5.1]
def change
reversible do |dir|
dir.up do
Applications.all.each do |app|
app.update(type: 'Service')
end
end
end
end
end
That’s it. Now your migration is baked in with the Application class and just became immutable (ideally how all migrations should be).
Thanks for reading!