ruby-on-railsrails-migrations

How does the Rails migration `change` method reverse its operations?


I have the following migration:

class AddMyColumn < ActiveRecord::Migration[6.1]
  def change
    add_column :my_table, :my_new_column, :bigint
    add_foreign_key :my_table, :my_other_table, column: :my_new_column
    add_index :my_table, :my_new_column
  end
end

When reversing this migration, I see this error:

Mysql2::Error: Cannot drop index 'index_my_table_on_my_new_column': needed in a foreign key constraint

The Rails guide explicitly says that a change migration using these actions should be reversible.

Re-ordering the add_foreign_key and add_index actions (or in this case, using add_reference) allows the migration to reverse successfully. However, this seems to contradict the documentation that states:

Active Record knows how to reverse a migration's actions automatically... [when using] actions that change supports. If you're going to need to use any other methods, you should use reversible or write the up and down methods instead of using the change method

add_column add_foreign_key & add_index are all supported actions.

Does the change method perform any analysis of the actions in order to reverse them appropriately? Or does it simply apply them in the reverse order? Is this behavior documented anywhere?


Solution

  • Does the change method perform any analysis of the actions in order to reverse them appropriately?

    There is a class that's responsible for reversing known methods:
    https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html#method-i-inverse_of


    Or does it simply apply them in the reverse order? Is this behavior documented anywhere?

    Migration methods are executed from bottom up inside the change method (which you can just see in the log).

    https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html#method-i-revert

    While executing the given block, the recorded will be in reverting mode. All commands recorded will end up being recorded reverted and in reverse order.