macsplean
macsplean

Reputation: 609

reversible and revert in Active Record migrations

I have looked at Rails Guides and the Rails API and I can't understand the usage of reversible and revert.

So for example, see the example linked here http://guides.rubyonrails.org/migrations.html#using-reversible and included below:\

It says Complex migrations may require processing that Active Record doesn't know how to reverse. You can use reversible to specify what to do when running a migration what else to do when reverting it. For example,

class ExampleMigration < ActiveRecord::Migration
  def change
    create_table :products do |t|
      t.references :category
    end

reversible do |dir|
  dir.up do
    #add a foreign key
    execute <<-SQL
      ALTER TABLE products
        ADD CONSTRAINT fk_products_categories
        FOREIGN KEY (category_id)
        REFERENCES categories(id)
    SQL
  end
  dir.down do
    execute <<-SQL
      ALTER TABLE products
        DROP FOREIGN KEY fk_products_categories
    SQL
  end
end

add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end

I get that the code in the down section is what will be run on rollback, but why include the code in the up block? I have also seen another example which had a reversible section with only an up block. What would the purpose of such code be?

Finally, I do not understand revert. Below is the example included in the Rails Guides, but it makes little sense to me.

`The revert method also accepts a block of instructions to reverse. This could be useful to revert selected parts of previous migrations. For example, let's imagine that ExampleMigration is committed and it is later decided it would be best to serialize the product list instead. One could write:
class SerializeProductListMigration < ActiveRecord::Migration
  def change
    add_column :categories, :product_list


reversible do |dir|
      dir.up do
        # transfer data from Products to Category#product_list
      end
      dir.down do
        # create Products from Category#product_list
      end
    end

    revert do
      # copy-pasted code from ExampleMigration
      create_table :products do |t|
        t.references :category
      end

      reversible do |dir|
        dir.up do
          #add a foreign key
          execute <<-SQL
            ALTER TABLE products
              ADD CONSTRAINT fk_products_categories
              FOREIGN KEY (category_id)
              REFERENCES categories(id)
          SQL
        end
        dir.down do
          execute <<-SQL
            ALTER TABLE products
              DROP FOREIGN KEY fk_products_categories
          SQL
        end
      end

      # The rest of the migration was ok
    end
  end
end`

Upvotes: 3

Views: 1310

Answers (2)

CodeMonkey
CodeMonkey

Reputation: 1

I read the rails guide. the version is v7.1.2

If you use the revert

  def change
    revert do
      # copy-pasted code from ExampleMigration
      reversible do |direction|
        direction.up do
          add_column :apples, :address, :string
        end
        direction.down do
          remove_column :apples, :address
        end
      end

      # The rest of the migration was ok
    end
  end

if you use the revessible like this

 def change
    reversible do |direction|
      change_table :apples do |_t|
        direction.up   { remove_column :apples, :address }
        direction.down { add_column :apples, :address, :string }
      end
    end
  end

for the follows,

  • The same migration could also have been written without using revert but this would have involved a few more steps: reversing the order of create_table and reversible, replacing create_table by drop_table, and finally replacing up by down and vice-versa. This is all taken care of by revert.

Upvotes: 0

Peter Alfvin
Peter Alfvin

Reputation: 29399

I'm not an expert in this by any means, but my understanding from reading the guides is as follows:

The reversible call in the first example is expressing the second of four components of the change migration. (Note: The indentation you have is misleading in this regard and should probably be updated to match the guide.) It is related to but distinct from the other components, so it makes sense that it would have both an up and down section. I can't explain why you would have reversible with only one direction and not the other, as you indicated you'd seen.

The revert call is telling the system to revert a previous migration either by name or by providing a block describing the (forward) migration. The example you showed is the latter case and I think is best understood by careful reading of the paragraph that follows it in the guide, to wit:

The same migration could also have been written without using revert but this would have involved a few more steps: reversing the order of create_table and reversible, replacing create_table by drop_table, and finally replacing up by down and vice-versa. This is all taken care of by revert.

Upvotes: 1

Related Questions