ruby on rails - migrations - ¿Cuál es la sintaxis correcta para remove_index en una migración de Rails 3.1.0?
rollback migration rails (6)
Estoy en el proceso de agregar Devise a una aplicación Rails existente, con una tabla de Usuarios ya definida. El generador de dispositivos expulsó la siguiente migración:
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
La migración a la baja no se genera, y estoy teniendo mucho tiempo eliminando esos índices. Estoy viendo diferentes notaciones sugeridas en la documentación y diferentes sugerencias en línea, pero ninguna de ellas parece funcionar 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 reviso la base de datos, estoy seguro que ''index_users_on_email'' está justo ahí ...
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 corriendo Rails 3.1.0, Ruby 1.9.2, rastrillo 0.9.2.2, con Postgres.
El comando que me está decepcionando es:
bundle exec rake db:rollback STEP=1
después de aplicar con éxito la migración hacia arriba. ¿Algún consejo?
Aquí está mi ejecución completa de esto (en Rails 5):
Tengo team_id como un índice en proveedores de tablas. Ya no necesito esta relación. Deshacerse de eso. Hizo lo siguiente:
1) crear la migración.
$ rails generate migration RemoveTeam_idFromVendor team_id:integer
2) Ejecutando la migración, dame este error. Y eso es porque la tabla de proveedores tiene filas cuya clave externa hace referencia al valor de clave principal de la tabla de 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 poner en marcha la migración, 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) ==================
Dependiendo del tipo de base de datos, no debe 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
Me gustaría ampliar la respuesta de @ iWasRobbed. Si tiene un índice en una sola columna, entonces preocuparse por remove_index
no tiene sentido ya que (¡solo una suposición!) La base de datos debería ser lo suficientemente inteligente como para limpiar los recursos utilizados por ese índice. Pero en caso de que tenga varias columnas, el índice de eliminación de la columna lo reducirá a las columnas aún existentes, lo cual es una cosa totalmente sensata de hacer, pero el tipo de muestra donde puede usar explícitamente remove_index
.
Solo a modo de ilustración: la migración a continuación tiene la falla de que después de ser aplicada arriba y abajo dejará el índice único en el email
(lo que significa que 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
Cambiando el bloque de down
a
def down
remove_index :users, [:email, :action_name]
remove_column :users, :action_name
end
solucionará esa falla y permitirá que la migración regrese correctamente el DB al estado anterior con rake db:rollback
Para alterar una tabla y / o sus índices, use #change_table
dentro de #change
action de una migración. Entonces podrás 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 tenga que eliminar una tabla con su índice de curso con acción #drop_table
puede usar el método SchemaStatements
para SchemaStatements
con el método #index
de Table
clase Table
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 necesite exactamente el #up/down
par #up/down
en una migración. Use solo un método #change_table
junto con el método #remove_index
de Table
clase Table
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 la versión Rails
de 2.1.0
o en versiones anteriores.
Para el registro, la forma de eliminar un índice por nombre es
remove_index(:table_name, :name => ''index_name'')
así que en tu caso
remove_index(:users, :name => ''index_users_on_email'')
También puede eliminar el índice especificando las columnas, que desde mi punto de vista es menos propenso a errores que escribir el nombre
remove_index :actions, :column => [:user_id, :action_name]