2012-01-27 12 views
59

Estoy en el proceso de agregar Devise a una aplicación de Rails existente, con una tabla de Usuarios ya definida. El generador legado empujó el siguiente migración:¿Cuál es la sintaxis correcta para remove_index en una migración de 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 

no se genera la migración descendente, y yo estoy teniendo un infierno de tiempo para la eliminación de esos índices. Estoy viendo diferentes notación sugerida en la documentación, y diferentes sugerencias en línea, pero ninguna de ellas parece estar funcionando para mí. Por ejemplo ...

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 

resultados en ...

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

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

lo cual es extraño, porque si puedo comprobar la base de datos, por supuesto, 'index_users_on_email' está ahí ...

que he probado otras variaciones, incluyendo

remove_index :users, :column => :email 

remove_index :users, 'email' 

o:

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

... pero no hay dados. Estoy ejecutando Rails 3.1.0, Ruby 1.9.2, rastrillo 0.9.2.2, con Postgres.

El comando que me está defraudando es:

bundle exec rake db:rollback STEP=1 

después de aplicar con éxito la migración hacia arriba. ¿Algún consejo?

+0

También recuerde primero quitar el índice y luego quitar la columna, sus códigos hacen al revés y fallarán incluso si usa una sintaxis correcta. –

Respuesta

41

Dependiendo del tipo de base de datos, no necesita preocuparse por eliminar los índices en el método self.down ya que el índice se eliminará automáticamente de la base de datos cuando suelte la columna.

También puede utilizar esta sintaxis en su método self.down:

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

Según la respuesta a esta pregunta, los índices no se eliminarán cuando suelte la columna: http://stackoverflow.com/questions/7204476/will-removing-a-column-with-a-rails-migration-remove- indexes-associated-with-the – Solomon

+0

^Depende del tipo de base de datos – iwasrobbed

+0

Para seguir la respuesta de @iwasrobbed, tenga cuidado con este enfoque. Si tiene un índice compuesto y solo elimina una de las columnas en MySQL, aún abandonará el índice. Solo hará referencia a la (s) columna (s) restante (s). La respuesta a continuación es un enfoque mucho más seguro para eliminar explícitamente el índice. – gordysc

148

Para el registro, la forma de eliminar un índice por su nombre es

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

por lo que en su caso

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

Para copiar y pegar con la sintaxis más reciente: 'remove_index: users, name: 'index_users_on_email'' – Chambeur

54

También puede eliminar el índice que especifica las columnas, que desde mi punto de vista es menos errar o propensos que escribir el nombre

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

Para la pregunta, esto sería' remove_index: users, column:: email'. – Will

5

me gustaría ampliar sobre la respuesta de @ iWasRobbed. Si tiene índice en una sola columna, preocuparse por remove_index no tiene sentido ya que (¡solo una suposición!), La base de datos debe ser lo suficientemente inteligente como para limpiar los recursos utilizados por ese índice. Pero en caso de que tenga varias columnas, el índice al eliminar la columna reducirá el índice a las columnas existentes, lo cual es una decisión totalmente sensata, pero muestra el tipo en el que podría desear utilizar remove_index explícitamente.

Sólo para ilustración - la migración de abajo tiene ese defecto que después de ser aplicada arriba y abajo dejará el índice único en email (es decir, la parte down no está haciendo su trabajo correctamente)

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 

Cambio de la down bloque para

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

solucionará ese defecto y permitir la migración para volver correctamente DB al estado anterior con rake db:rollback

0

Para modificar una tabla y/o sus indeces use #change_table dentro de #change acción de una migración. A continuación, será capaz de crear la eliminación del índice reversible de la siguiente manera:

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

Cuando hay que eliminar una tabla con su índice, por supuesto, con la acción reversible puede utilizar #drop_table método para SchemaStatements con el método de Table clase #index para ConnectionAdapter :

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

en caso de que las necesitan exactamente el par #up/down en una migración. Utilizar sólo un método #change_table junto con #remove_index método de Table clase para 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 

Todos los métodos están disponibles en versión de Rails2.1.0 o de los anteriores.

0

Aquí es mi carrera completa de este (en los carriles 5):

He team_id como un índice en la tabla de proveedores. Ya no necesito esta relación. Deshacerse de eso. Hizo lo siguiente:

1) cree la migración.

$ rails generate migration RemoveTeam_idFromVendor team_id:integer 

2) Ejecutando la migración, deme este error. Y eso se debe a que tabla de proveedores tiene filas cuyas referencias clave externa del valor de la clave primaria de la tabla equipo

== 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) Para resolver esto y conseguir la migración correr, hice lo siguiente (Nota: estoy en 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) ================== 
Cuestiones relacionadas