Каков правильный синтаксис для удаления индекса в миграции Rails 3.1.0?
Я в процессе добавления Devise в существующее приложение Rails, с уже определенной таблицей пользователей. Генератор devise выталкивал следующую миграцию:
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
после успешного применения миграции вверх. Какие-нибудь советы?
6 ответов:
в зависимости от типа базы данных, вам не нужно беспокоиться об удалении индексов в
self.down
метод, так как индекс будет автоматически удален из базы данных при удалении столбца.вы также можете использовать этот синтаксис в
self.down
способ:def self.down remove_column :users, :email remove_column :users, :encrypted_password remove_column :users, :reset_password_token end
для записи, способ удалить индекс по имени
remove_index(:table_name, :name => 'index_name')
Так что в вашем случае
remove_index(:users, :name => 'index_users_on_email')
вы также можете удалить индекс, указывающий столбцы, которые, с моей точки зрения, менее подвержены ошибкам, чем запись имени
remove_index :actions, :column => [:user_id, :action_name]
Я хочу, чтобы развернуть на ответ @iWasRobbed по. Если у вас есть индекс только на один столбец, то беспокоиться о
remove_index
не имеет смысла так как (просто Успенской!) БД должна быть достаточно умной, чтобы очистить ресурсы, используемые этим индексом. Но в случае, если у вас есть несколько столбцов индекса удаление столбца приведет к уменьшению индекса до все еще существующих столбцов, что совершенно разумно, но вид показывает, где вы можете использоватьremove_index
явно.просто для иллюстрация-миграция ниже имеет тот недостаток, что после применения вверх и вниз он оставит уникальный индекс на
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
чтобы изменить таблицу и / или ее indeces использовать
#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
или более ранних.
вот мой полный запуск этого(в 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) ==================