¿Cómo se escribe una migración para cambiar el nombre de un modelo ActiveRecord y su tabla en Rails?

408

Soy terrible para nombrar y me doy cuenta de que hay un mejor conjunto de nombres para mis modelos en mi aplicación Rails.
¿Hay alguna forma de usar una migración para cambiar el nombre de un modelo y su tabla correspondiente?

Solo lectura
fuente
11
Sugerí agregar "ActiveRecord" a esta pregunta para mejorar las coincidencias en los motores de búsqueda. He estado buscando esto usando la "tabla de cambio de nombre de ActiveRecord".
Landon Kuhn el
66
Si está utilizando migraciones, este problema es más complicado de lo que parece. La solución seleccionada dice que solo regrese y cambie manualmente el nombre del modelo, controlador, etc. después de haber cambiado el nombre de la tabla. Si hace esto, todas las migraciones anteriores que se refieren a su modelo por su nombre anterior fallarán. Entonces, cuando alguien clona tu repositorio e intenta ejecutar rake db:migrate, fallará. Podrías regresar y cambiar esos nombres en la migración, pero eso se volverá complicado. Puede que sea mejor crear un modelo completamente nuevo en lugar de cambiarle el nombre.
Andrew
44
@andrewhannigan: ¿No es discutible si alguien clona tu repositorio y solo corre rake db:schema:load?
istrasci
3
@istrasci: absolutamente. De hecho, correr rake db:migratepara configurar una base de datos desde cero se desaconseja activamente, exactamente debido a las preocupaciones señaladas por Andrew.
Giuseppe

Respuestas:

584

Aquí hay un ejemplo:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def self.up
    rename_table :old_table_name, :new_table_name
  end

  def self.down
    rename_table :new_table_name, :old_table_name
  end
end

Tuve que ir y cambiar el nombre del archivo de declaración del modelo manualmente.

Editar:

En Rails 3.1 y 4, ActiveRecord::Migration::CommandRecordersabe cómo revertir las migraciones rename_table, por lo que puede hacer esto:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def change
    rename_table :old_table_name, :new_table_name
  end 
end

(Todavía tiene que revisar y renombrar manualmente sus archivos).

Solo lectura
fuente
66
@mathee: sí, debe cambiarlo manualmente, o usar un IDE que pueda refactorizar Ruby y confirmarlo en su sistema de control de versiones.
pupeno
13
Git Grep es tu amigo. Estoy cambiando el nombre de una actividad a un hábito en este momento: git grep -i activites muy revelador.
Felix Rabe
1
También debes cambiar el contenido de tu controlador, ¿verdad?
alemur
55
¡Y no olvides tus rutas.rb!
Dan Herman el
26
Además, solo como aviso, desea utilizar la versión plural del nombre de su tabla en la llamada rename_table.
Han
66

En Rails 4 todo lo que tenía que hacer era el cambio de definición

def change
  rename_table :old_table_name, :new_table_name
end

Y todos mis índices fueron atendidos por mí. No necesitaba actualizar manualmente los índices eliminando los antiguos y agregando nuevos.

Y funciona utilizando el cambio para subir o bajar en lo que respecta a los índices también.

bfcoder
fuente
47

Las otras respuestas y comentarios cubrieron el cambio de nombre de la tabla, el cambio de nombre de archivo y el grepping a través de su código.

Me gustaría agregar algunas advertencias más:

Usemos un ejemplo del mundo real que enfrenté hoy: cambiar el nombre de un modelo de 'Comerciante' a 'Negocio'.

  • No olvide cambiar los nombres de tablas y modelos dependientes en la misma migración. Cambié mis modelos Merchant y MerchantStat a Business y BusinessStat al mismo tiempo. De lo contrario, habría tenido que hacer demasiadas elecciones al realizar búsquedas y reemplazos.
  • Para cualquier otro modelo que dependa de su modelo mediante claves externas, los nombres de columna de clave externa de las otras tablas se derivarán del nombre del modelo original. Por lo tanto, también querrá hacer algunas llamadas rename_column en estos modelos dependientes. Por ejemplo, tuve que cambiar el nombre de la columna 'merchant_id' a 'business_id' en varias tablas de unión (para la relación has_and_belongs_to_many) y otras tablas dependientes (para las relaciones has_one y has_many normales). De lo contrario, habría terminado con columnas como 'business_stat.merchant_id' apuntando a 'business.id'. Aquí hay una buena respuesta sobre cómo cambiar el nombre de las columnas.
  • Al grepping, recuerde buscar versiones singulares, plurales, en mayúsculas, minúsculas e incluso MAYÚSCULAS (que pueden aparecer en los comentarios) de sus cadenas.
  • Es mejor buscar versiones en plural primero, luego en singular. De esa manera, si tiene un plural irregular, como en mis comerciantes :: ejemplo de negocios, puede obtener todos los plurales irregulares correctos. De lo contrario, puede terminar con, por ejemplo, 'negocios' (3 s) como un estado intermedio, lo que resulta en aún más búsqueda y reemplazo.
  • No reemplace ciegamente cada ocurrencia. Si los nombres de sus modelos chocan con términos de programación comunes, con valores en otros modelos o con contenido textual en sus vistas, puede terminar demasiado ansioso. En mi ejemplo, quería cambiar el nombre de mi modelo a 'Negocios' pero aún referirme a ellos como 'comerciantes' en el contenido de mi interfaz de usuario. También tuve un rol de 'comerciante' para mis usuarios en CanCan: fue la confusión entre el rol de comerciante y el modelo de comerciante lo que me llevó a cambiar el nombre del modelo en primer lugar.
armchairdj
fuente
26

También debe reemplazar sus índices:

class RenameOldTableToNewTable< ActiveRecord:Migration
  def self.up
    remove_index :old_table_name, :column_name
    rename_table :old_table_name, :new_table_name
    add_index :new_table_name, :column_name
  end 

  def self.down
    remove_index :new_table_name, :column_name
    rename_table :new_table_name, :old_table_name
    add_index :old_table_name, :column_name
  end
end

Y cambie el nombre de sus archivos, etc., manualmente, como lo describen otras respuestas aquí.

Ver: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

Asegúrese de que puede retroceder y avanzar después de escribir esta migración. Puede ser complicado si te equivocas y te atascas con una migración que intenta efectuar algo que ya no existe. Es mejor que descarte toda la base de datos y comience nuevamente si no puede retroceder. Tenga en cuenta que es posible que deba respaldar algo.

Además: revise schema_db para ver cualquier nombre de columna relevante en otras tablas definidas por un has_ ​​o belong_to o algo así. Probablemente también necesites editarlos.

Y finalmente, hacer esto sin un conjunto de pruebas de regresión sería una locura.

Rimian
fuente
11
En cuanto a las migraciones de rails 4.0.0.beta1, no es necesario actualizar los índices manualmente. AR lo actualiza solo.
freemanoid
1

Puede ejecutar este comando: rails g migración rename_ {old_table_name} a {new_table_name}

después de editar el archivo y agregar este código en el cambio de método

rename_table: {old_table_name},: {new_table_name}

Mouhamadou Bamba Mboup
fuente