Database Migrations: Part II - Veltris

Database Migrations: Part II

November 6, 2020 | Bandana Pandey

    This is the second part of Database Migrations, after covering the basic terminology about migrations(what, why, how) in Database Migrations: Part I , in this blog we’ll go into deep dives on each of the following things:

    1. Reversible and Irreversible Migrations
    2. How to write safe migrations

    Reversible Migrations

    Our migration file specifically contains change method, which internally gets mapped to up method and down method.

    The up method will be executed when we run migration whereas down method will be executed when we’ll reverse our changes using rollback.

    By using change method, libraries like ActiveRecord and Ecto can by-default figure out how to reverse migrations, without us explicitly specifying up and down methods.

    For example, we are creating a users table by writing migrations like this in Rails

    class CreateUsers < ActiveRecord::Migration[6.0]
      def change
        create_table :users do |t|
          t.string :first_name, :null => false
          t.string :last_name
          t.string :email, :null => false
          t.timestamps
        end
      end
    end

    for the above case when we’ll run rake db:migrate, it will create a users table with specified columns, with following up method equivalent

    def up
       create_table :users do |t|
         t.string :first_name, :null => false
         t.string :last_name
         t.string :email, :null => false      
         t.timestamps    
       end  
    end

    and when we’ll run rake db:rollback, ActiveRecord will figure it out that it has to reverse this migrations, with following down method equivalent

    def down
      drop_table :users
    end

    These type of migrations, where ActiveRecord knows how to revert back(written inside change method), without us explicitly writing up and down methods are termed as reversible migrations.

    If we have multiple instructions in the change method, and when we’ll run db:migrate, ActiveRecord will run all the instructions from top to down. Also, when we rollback this(db:rollback) ActiveRecord will run reverse instructions from bottom to top.

    But there is one thing which we should always remember that not all migrations are reversible migrations, there are some migrations which ActiveRecord/Ecto does not know how to revert and these types of migrations are called irreversible migrations.

    Irreversible Migrations

    For eg, if we are using create_table, add_index, add_column then ActiveRecord will know that the reverse of this will be drop_table, remove_index, remove_column.

    But let’s be practical not all migrations will be simple like this, there will be use cases where we’ll have to write complex migrations. So, In order to understand this irreversible concept, let’s take an example

    def change
      change_column :orders, :price, :float
    end

    Here, we want to change the type of column price to float from integer. So when we’ll run this migration, it’ll change column type of price from integer to float and that is perfect…

    What if I want to revert this migration ?

    According to what we have learnt till now, you all must be thinking that ActiveRecord should revert this migration like how it does in case of create_table.

    So what is this whole drama about ?

    But my friends, we do have some problem here …

    Because, in this case ActiveRecord will not be able to revert price back to integer from float, as there is no track maintained by ActiveRecord(or our database schema)regarding price previous state(column_type) which is integer. So our rollback will fail miserably 🙁

    Now what to do in these type of scenarios?

    In order to avoid these situations, we should always write safe migrations.

    How to write safe migrations ?

    Safe migrations in our case means writing explicitly up and down methods like this:

    def up
      change_column :orders, :price, :float
    end
    def down
      change_column :orders, :price, :integer
    end

    By writing explicitly down method, we as a developer are making sure that our migrations whenever they’ll be reverted, our database will be moved to it previous stable state without failing or raising any error.

    In this case, when we’ll rollback it’ll change our price column_type to integer thus maintaining previous state of our database.

    How to write safe migrations ?

    In order to write safe migrations, we should always write explicitly up and down method instead of relying on change method and thinking that ActiveRecord/Ecto will handle everything for us.

    ActiveRecord/Ecto libraries are not magic, even-though they solve most of the cases, but there can be use-cases for which they’ll fail. So as a developer, it is our responsibility to think through every scenario and write better code.

    Reference Taken from: https://tenor.com/

    ❤️ Like, Share or Leave A Comment!

    Well, thats all for this blog, Hope you find it informative. If you liked it, please click the 👏🏼 button and share it with others! Feel free to leave any comments.
    For more such blogs … stay tuned.

    Happy Coding …

    Thanks

    Related Articles