Skip to Content Skip to Search

class ActiveRecord::Migration::CommandRecorder

Migration Command Recorder

ActiveRecord::Migration::CommandRecorder records commands done during a migration and knows how to reverse those commands. The CommandRecorder knows how to invert the following commands:

  • add_column

  • add_foreign_key

  • add_check_constraint

  • add_exclusion_constraint

  • add_unique_constraint

  • add_index

  • add_reference

  • add_timestamps

  • change_column_default (must supply a :from and :to option)

  • change_column_null

  • change_column_comment (must supply a :from and :to option)

  • change_table_comment (must supply a :from and :to option)

  • create_enum

  • create_join_table

  • create_table

  • disable_extension

  • drop_enum (must supply a list of values)

  • drop_join_table

  • drop_table (must supply a block)

  • enable_extension

  • remove_column (must supply a type)

  • remove_columns (must supply a :type option)

  • remove_foreign_key (must supply a second table)

  • remove_check_constraint

  • remove_exclusion_constraint

  • remove_unique_constraint

  • remove_index

  • remove_reference

  • remove_timestamps

  • rename_column

  • rename_enum (must supply a :to option)

  • rename_enum_value (must supply a :from and :to option)

  • rename_index

  • rename_table

Constants

ReversibleAndIrreversibleMethods

[
:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
:rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
:change_column_default, :add_reference, :remove_reference, :transaction,
:drop_join_table, :drop_table, :execute_block, :enable_extension, :disable_extension,
:change_column, :execute, :remove_columns, :change_column_null,
:add_foreign_key, :remove_foreign_key,
:change_column_comment, :change_table_comment,
:add_check_constraint, :remove_check_constraint,
:add_exclusion_constraint, :remove_exclusion_constraint,
:add_unique_constraint, :remove_unique_constraint,
:create_enum, :drop_enum, :rename_enum, :add_enum_value, :rename_enum_value,
]

Attributes

[RW] commands
[RW] delegate
[RW] reverting

Public class methods

new(delegate = nil)

Permalink
Source code GitHub
# File activerecord/lib/active_record/migration/command_recorder.rb, line 63
def initialize(delegate = nil)
  @commands = []
  @delegate = delegate
  @reverting = false
end

Public instance methods

inverse_of(command, args, &block)

Permalink

Returns the inverse of the given command. For example:

recorder.inverse_of(:rename_table, [:old, :new])
# => [:rename_table, [:new, :old]]

If the inverse of a command requires several commands, returns array of commands.

recorder.inverse_of(:remove_columns, [:some_table, :foo, :bar, type: :string])
# => [[:add_column, :some_table, :foo, :string], [:add_column, :some_table, :bar, :string]]

This method will raise an IrreversibleMigration exception if it cannot invert the command.

Source code GitHub
# File activerecord/lib/active_record/migration/command_recorder.rb, line 110
      def inverse_of(command, args, &block)
        method = :"invert_#{command}"
        raise IrreversibleMigration, <<~MSG unless respond_to?(method, true)
          This migration uses #{command}, which is not automatically reversible.
          To make the migration reversible you can either:
          1. Define #up and #down methods in place of the #change method.
          2. Use the #reversible method to define reversible behavior.
        MSG
        send(method, args, &block)
      end

record(*command, &block)

Permalink

Record command. command should be a method name and arguments. For example:

recorder.record(:method_name, [:arg1, :arg2])
Source code GitHub
# File activerecord/lib/active_record/migration/command_recorder.rb, line 90
def record(*command, &block)
  if @reverting
    @commands << inverse_of(*command, &block)
  else
    @commands << (command << block)
  end
end

replay(migration)

Permalink
Source code GitHub
# File activerecord/lib/active_record/migration/command_recorder.rb, line 144
def replay(migration)
  commands.each do |cmd, args, block|
    migration.send(cmd, *args, &block)
  end
end

revert()

Permalink

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. For example:

recorder.revert{ recorder.record(:rename_table, [:old, :new]) }
# same effect as recorder.record(:rename_table, [:new, :old])
Source code GitHub
# File activerecord/lib/active_record/migration/command_recorder.rb, line 76
def revert
  @reverting = !@reverting
  previous = @commands
  @commands = []
  yield
ensure
  @commands = previous.concat(@commands.reverse)
  @reverting = !@reverting
end

Definition files