2012-01-27 2 views
59

Я в процессе добавления Devise к существующему Rails-приложению с уже определенной таблицей Users. Генератор Разрабатывают выталкивается следующий переход:Какой правильный синтаксис для remove_index в миграции Rails 3.1.0?

class AddDeviseToUsers < ActiveRecord::Migration 
    def self.up 
    change_table(:users) do |t| 

    ## Database authenticatable 
    t.string :email,    :null => false, :default => "" 
    t.string :encrypted_password, :null => false, :default => "" 

    ## Recoverable 
    t.string :reset_password_token 
    t.datetime :reset_password_sent_at 

    ## Rememberable 
    t.datetime :remember_created_at 

    ## Trackable 
    t.integer :sign_in_count, :default => 0 

    blah blah blah.... 

    end 

    add_index :users, :email,    :unique => true 
    add_index :users, :reset_password_token, :unique => true 
end 

вниз миграция не генерируется, и у меня чертовски времени удаления этих индексов. Я вижу разные предложения в документации и различные предложения в Интернете, но ни один из них, похоже, не работает для меня. Например ...

def self.down 
    change_table(:users) do |t| 
    t.remove :email 
    t.remove :encrypted_password 

    t.remove :reset_password_token 

    blah blah blah... 
    end 

    remove_index :users, :email 
    remove_index :users, :reset_password_token 
end 

приводит ...

An error has occurred, this and all later migrations canceled: 

Index name 'index_users_on_email' on table 'users' does not exist 

что странно, потому что если я проверить базу данных, конечно же, 'index_users_on_email' право есть ...

я пробовал другие варианты, в том числе

remove_index :users, :column => :email 

remove_index :users, 'email' 

или:

change_table(:users) do |t| 
    t.remove_index :email 
end 

... но не кости. Я запускаю Rails 3.1.0, Ruby 1.9.2, rake 0.9.2.2, с Postgres.

Команда, которая позволить мне вниз:

bundle exec rake db:rollback STEP=1 

после успешного применения миграции вверх. Любой совет?

+0

Также помните, что сначала удалите индекс, а затем удалите столбец, ваши коды будут действовать наоборот и не удастся, даже если вы используете правильный синтаксис. –

ответ

41

В зависимости от типа базы данных вам не нужно беспокоиться об удалении индексов в методе self.down, поскольку индекс будет автоматически удален из базы данных при удалении столбца.

Вы также можете использовать этот синтаксис в методе self.down:

def self.down 
    remove_column :users, :email 
    remove_column :users, :encrypted_password 
    remove_column :users, :reset_password_token 
end 
+8

Основываясь на ответе на этот вопрос, индексы не будут удалены при удалении столбца: http://stackoverflow.com/questions/7204476/will-removing-a-column-with-a-rails-migration-remove- indexes-associated-with-the – Solomon

+0

^Зависит от типа базы данных – iwasrobbed

+0

Для дальнейшего ответа @iwasrobbed будьте осторожны с этим подходом. Если у вас есть составной индекс и только удалить один из столбцов в MySQL, он все равно оставит индекс. Это будет просто ссылка на оставшиеся столбцы. Ответ ниже - гораздо более безопасный подход, чтобы явно удалить индекс. – gordysc

148

Для записи, способ удаления индекса по имени является

remove_index(:table_name, :name => 'index_name') 

так в вашем случае

remove_index(:users, :name => 'index_users_on_email') 
+6

Для copy-paster с более новым синтаксисом: 'remove_index: users, name: 'index_users_on_email'' – Chambeur

54

Вы также можете удалить индекс, указав столбцы, которые с моей точки зрения меньше err или подвержены, чем написание имени

remove_index :actions, :column => [:user_id, :action_name] 
+8

Для вопроса это будет' remove_index: users, column:: email'. – Will

5

Я хотел бы расширить ответ на @ iWasRobbed. Если у вас есть индекс только для одного столбца, то беспокоиться о remove_index не имеет смысла с тех пор (просто предположение!) БД должна быть достаточно умна, чтобы очищать ресурсы, используемые этим индексом. Но в случае, если у вас есть несколько столбцов, индекс, удаляющий столбец, уменьшит индекс до все еще существующих столбцов, что вполне разумно, но какие-то шоу, где вы можете явно использовать remove_index.

Просто для иллюстрации - миграция ниже, имеет тот недостаток, что после нанесения вверх и вниз, он оставит уникальный индекс на email (имеется в виде down части не выполняет свою работу должным образом)

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 

Изменения down блок для

def down 
    remove_index :users, [:email, :action_name] 
    remove_column :users, :action_name 
    end 

исправит этот недостаток и позволяет миграции правильно вернуть БД в предыдущее состояние с rake db:rollback

0

Чтобы изменить таблицу и/или ее показатели, используйте #change_table внутри #change действие миграции. После этого вы сможете создать обратимое удаление индекса следующим образом:

def change 
    change_table :users do |t| 
     t.index :email, :unique => true 
     t.index :reset_password_token, :unique => true 
    end 
end 

Когда вы должны удалить таблицу с индексом, конечно, с обратимым действием вы можете использовать #drop_table метод SchemaStatements с #index методом Table класса для ConnectionAdapter :

def change 
    drop_table :users do |t| 
     t.index :email, :unique => true 
     t.index :reset_password_token, :unique => true 
    end 
end 

В случае, если у вас есть потребность в точности #up/down пара в миграции. Используйте только метод #change_table наряду с #remove_index методом Table класса для 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 

Все методы доступны в Rails версии 2.1.0 или более ранних.

0

Вот мой полный пробег этого (в Rails 5):

Я team_id в качестве индекса в поставщиках таблицы. Мне больше не нужно это отношение. Чтобы избавиться от него. Сделал следующее:

1) создать миграцию.

$ rails generate migration RemoveTeam_idFromVendor team_id:integer 

2) Выполняя миграцию, дайте мне эту ошибку. И это потому, что таблица поставщик имеет строки, в которых внешний ключ ссылается на первичный ключ таблицы команды

== 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) Для того, чтобы решить эту проблему и получить миграционную работает, я сделал следующее (Примечание: я нахожусь в 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) ================== 
Смежные вопросы