Какой правильный синтаксис для remove_index в Rails 3.1.0 миграции? - PullRequest
64 голосов
/ 27 января 2012

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

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, рейк 0.9.2.2, с Postgres.

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

bundle exec rake db:rollback STEP=1

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

Ответы [ 6 ]

154 голосов
/ 12 июля 2012

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

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

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

remove_index(:users, :name => 'index_users_on_email')
58 голосов
/ 02 октября 2012

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

remove_index :actions, :column => [:user_id, :action_name]
44 голосов
/ 27 января 2012

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

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

def self.down
   remove_column :users, :email
   remove_column :users, :encrypted_password
   remove_column :users, :reset_password_token
end
5 голосов
/ 15 ноября 2013

Я хотел бы подробнее остановиться на ответе @ 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 голосов
/ 28 июля 2017

Вот мой полный прогон этого (в 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) ==================
0 голосов
/ 26 ноября 2015

Чтобы изменить таблицу и / или ее индексы, используйте #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_tableSchemaStatements с методом #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 или более ранних.

...