How does rails knows that migration is pending?

iamronakgupta

Ronak Gupta

Posted on May 11, 2024

How does rails knows that migration is pending?

You might have enountered an condition of migration pending when you are trying to access a route, we may wonder sometime how does rails knows that migrations are pending.

Image showing pending migration error in browser

Rails keeps the track of every migration that has been ran in a table schema_migration. This table has only one column version that store the version of migration files.

Image showing data from schema_migration table

Versions are the creation timestamp of migration file, this version makes every migration unique from each other. So every time we runs a migration, corresponding version are stored in this table and whenever we runs a rollback corresponding version are removed from the table.

How schema_migration table is created

If we check the source of code of activerecord gem, we can see SchemaMigration class. This class is reponsible for table creation and all related operation like insertion and deletion in the table.

Some important method from SchemaMigration class

class SchemaMigration # :nodoc:
    class NullSchemaMigration # :nodoc:
    end

    attr_reader :arel_table

    def initialize(pool)
      @pool = pool
      @arel_table = Arel::Table.new(table_name)
    end

    def create_version(version)
      im = Arel::InsertManager.new(arel_table)
      im.insert(arel_table[primary_key] => version)
      @pool.with_connection do |connection|
        connection.insert(im, "#{self.class} Create", primary_key, version)
      end
    end

    def delete_version(version)
      dm = Arel::DeleteManager.new(arel_table)
      dm.wheres = [arel_table[primary_key].eq(version)]

      @pool.with_connection do |connection|
        connection.delete(dm, "#{self.class} Destroy")
      end
    def create_table
      @pool.with_connection do |connection|
        unless connection.table_exists?(table_name)
          connection.create_table(table_name, id: false) do |t|
            t.string :version, **connection.internal_string_options_for_primary_key
          end
        end
      end
    end
end
Enter fullscreen mode Exit fullscreen mode

In above code, create_table create a table in database and create_version inserts version in table and delete_version removes version from table. Other method are also available in source code.

How does rails raise pending migration error

In Migration class in activerecord gem there is class available CheckPending

call method from CheckPending class

  def call(env)
        mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
        if @last_check < mtime
          ActiveRecord::Migration.check_pending!(connection)
          @last_check = mtime
        end
        @app.call(env)
      end
Enter fullscreen mode Exit fullscreen mode

This call method in CheckPending class calls an another method of Migration class check_pending!

Some methods from Migration class

def check_pending!(connection = Base.connection)
        raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
      end

def needs_migration?
  (migrations.collect(&:version) - get_all_versions).size > 0
end

def get_all_versions
   if SchemaMigration.table_exists?
     SchemaMigration.all_versions.map(&:to_i)
   else
     []
   end
end
Enter fullscreen mode Exit fullscreen mode

In above code, check_pending! calls the need_migration? method that calls the get_all_versions method. get_all_versions method with the help of SchemaMigration give all version to need_migration? method which check if number of migration files are equal to number of versions available in schema_migration table. If schema_migration table have less numbers of version it means there are some pending migration.

Migration class also have an another class PendingMigrationError which have details of error for pending migrations.

CheckPending and PendingMigrationError classes are accessed from railtie class during initialization.

Conclusion

In conclusion, ruby on rails are designed with detailing to ensure its smoothness and thats what makes it different from other frameworks.

I would love to know your reviews on this article. If you liked it or if you have any suggestion please put a comment.

💖 💪 🙅 🚩
iamronakgupta
Ronak Gupta

Posted on May 11, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related