I\'m in the process of adding Devise to an existing Rails app, with a Users table already defined. The devise generator pushed out the following migration:
class
Depending on the database type, you don't need to worry about removing the indexes in the self.down
method since the index will automatically be removed from the database when you drop the column.
You can also use this syntax in your self.down
method:
def self.down
remove_column :users, :email
remove_column :users, :encrypted_password
remove_column :users, :reset_password_token
end
Here is my full run of this(in Rails 5):
I have team_id as an index in table vendors. I no longer need this relation. To get rid of it. Did the following:
1) create the migration.
$ rails generate migration RemoveTeam_idFromVendor team_id:integer
2) Running the migration, give me this error. And that is because vendor table has rows whose foreign key references the primary key value of the team table
== 20170727202815 RemoveTeamIdFromVendor: migrating ===========================
-- remove_column(:vendors, :team_id, :integer)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "vendors"
3) To solve this and get the migration running, I did the following(Note: i am in dev):
$ rake db:drop
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
$ rake db:create
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
$ rake db:migrate
~
~
~
== 20170727202815 RemoveTeamIdFromVendor: migrating ===========================
-- remove_column(:vendors, :team_id, :integer)
-> 0.0185s
== 20170727202815 RemoveTeamIdFromVendor: migrated (0.0185s) ==================
I'd like to expand on @iWasRobbed's answer. If you have index on just single column then worrying about remove_index
doesn't make sense since (just an assumtion!) the DB should be smart enough to cleanup the resources used by that index. But in case you have multiple columns index removing the column will reduce index to still existing columns, which is totally sensible thing to do, but kind of shows where you might want to use remove_index
explicitely.
Just for illustration - migration below has that flaw that after being applied up and down it will leave the unique index on email
(meaning the down
part is not doing its job properly)
class AddIndexes < ActiveRecord::Migration
def up
add_column :users, :action_name, :string
add_index :users, [:email, :action_name], unique: true
end
def down
remove_column :users, :action_name
end
end
Changing the down
block to
def down
remove_index :users, [:email, :action_name]
remove_column :users, :action_name
end
will fix that flaw and allow the migration to correctly return DB to the previous state with rake db:rollback
To alter a table and/or its indeces use #change_table inside #change
action of a migration. Then you be able to create reversable index removal as follows:
def change
change_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
When you have to drop a table with its index of course with reversable action you can use #drop_table method for SchemaStatements
with the #index method of Table
class for ConnectionAdapter
:
def change
drop_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
In case you have need exactly the #up/down
pair in a migration. Use just a #change_table method along with #remove_index method of Table
class for ConnectionAdapter
:
def up
change_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
def down
change_table :users do |t|
t.remove_index :email, :unique => true
t.remove_index :reset_password_token, :unique => true
end
end
All of the methods are available in Rails
version of 2.1.0
or of earlier ones.
For the record, the way to remove an index by name is
remove_index(:table_name, :name => 'index_name')
so in your case
remove_index(:users, :name => 'index_users_on_email')
You can also remove the index specifying the columns, which from my point of view is less error prone than writing the name
remove_index :actions, :column => [:user_id, :action_name]