¿Cómo puedo cambiar el nombre de una columna de base de datos en una migración de Ruby on Rails?

Respuestas:

2309
rename_column :table, :old_column, :new_column

Probablemente desee crear una migración separada para hacer esto. (Renombra FixColumnNamecomo quieras):

script/generate migration FixColumnName
# creates  db/migrate/xxxxxxxxxx_fix_column_name.rb

Luego edite la migración para hacer su voluntad:

# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
  def self.up
    rename_column :table_name, :old_column, :new_column
  end

  def self.down
    # rename back if you need or do something else or do nothing
  end
end

Para Rails 3.1 use:

Mientras que los métodos upy downtodavía se aplican, Rails 3.1 recibe unchange método que "sabe cómo migrar su base de datos y revertirla cuando la migración se revierte sin la necesidad de escribir un método por separado".

Consulte " Migraciones de registros activos " para obtener más información.

rails g migration FixColumnName

class FixColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

Si tiene que cambiar un montón de columnas, o algo que hubiera requerido repetir el nombre de la tabla una y otra vez:

rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...

Podrías usar change_tablepara mantener las cosas un poco más ordenadas:

class FixColumnNames < ActiveRecord::Migration
  def change
    change_table :table_name do |t|
      t.rename :old_column1, :new_column1
      t.rename :old_column2, :new_column2
      ...
    end
  end
end

Luego, db:migratecomo de costumbre o como sea que vayas por tu negocio.


Para rieles 4:

Al crear un Migrationpara renombrar una columna, Rails 4 genera un changemétodo en lugar de upy downcomo se menciona en la sección anterior. El changemétodo generado es:

$ > rails g migration ChangeColumnName

que creará un archivo de migración similar a:

class ChangeColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
nowk
fuente
24
self.down siempre debe ser lo opuesto a self.up, por lo que "si necesita o hace otra cosa o no hace nada" no se recomienda realmente. Simplemente haga: rename_column: table_name,: new_column,: old_column
Luke Griffiths
3
Si bien es una práctica normal revertir lo que hiciste self.up, no diría self.down" siempre debería ser opuesto". En depende del contexto de su migración. Simplemente poner lo "opuesto" podría no ser la migración hacia abajo "correcta".
nowk
23
En Rails 3.1 puede reemplazar def self.upy def self.downcon def changey sabrá cómo deshacer.
Turadg
2
Turadg - * sabrá cómo retroceder la mayor parte del tiempo. Me parece que el changemétodo no es plena prueba, por lo que tienden a utilizar upy downmétodos para migraciones complejas.
JellyFishBoy
66
¿El cambio de nombre elimina el índice?
Sung Cho
68

En mi opinión, en este caso, es mejor usar rake db:rollback, luego editar la migración y volver a ejecutar rake db:migrate.

Sin embargo, si tiene datos en la columna que no desea perder, utilícelos rename_column.

elf.xf
fuente
34
Incluso en un "equipo de uno", si tiene varias instancias de su aplicación ejecutándose, por ejemplo, en diferentes entornos o en múltiples computadoras, etc., administrar migraciones editadas es un gran problema. Solo edito una migración si solo la creé y me di cuenta de que estaba mal, y no la he ejecutado literalmente en ningún otro lugar todavía.
Yetanotherjosh
1
Tuve que reiniciar el servidor después de eso.
Muhammad Hewedy
77
Esta técnica solo debe usarse en una situación en la que sus cambios aún no se hayan fusionado con su rama de producción, y otros no dependan de la persistencia de los datos. En la mayoría de las circunstancias de producción, este NO es el método preferido.
Collin Graves
44
Nunca hagas este tipo de cosas.
new2cpp
44
Me gusta decirle a mi equipo: 'Las migraciones son gratuitas'. El costo de editar una migración que se ha lanzado en la naturaleza es alto: una vez pasé unas horas averiguando por qué mi código no funcionaba antes de darme cuenta de otro miembro del equipo había regresado y editado una migración que ya había ejecutado. Así que no edite una migración existente, use una nueva para cambiar el esquema, porque ... '¡Las migraciones son gratuitas!' (no es estrictamente cierto, pero hace el punto)
TerryS
31

Si la columna ya está poblada con datos y vive en producción, recomendaría un enfoque paso a paso, para evitar el tiempo de inactividad en la producción mientras se esperan las migraciones.

Primero, crearía una migración de base de datos para agregar columnas con los nuevos nombres y llenarlas con los valores del nombre de la columna anterior.

class AddCorrectColumnNames < ActiveRecord::Migration
  def up
    add_column :table, :correct_name_column_one, :string
    add_column :table, :correct_name_column_two, :string

    puts 'Updating correctly named columns'
    execute "UPDATE table_name SET correct_name_column_one = old_name_column_one, correct_name_column_two = old_name_column_two"
    end
  end

  def down
    remove_column :table, :correct_name_column_one
    remove_column :table, :correct_name_column_two
  end
end

Entonces cometería ese cambio y empujaría el cambio a producción.

git commit -m 'adding columns with correct name'

Luego, una vez que el commit ha sido empujado a la producción, corría.

Production $ bundle exec rake db:migrate

Luego, actualizaría todas las vistas / controladores que hacían referencia al antiguo nombre de columna al nuevo nombre de columna. Ejecute mi conjunto de pruebas y confirme solo esos cambios. (¡Después de asegurarse de que funcionaba localmente y de aprobar todas las pruebas primero!)

git commit -m 'using correct column name instead of old stinky bad column name'

Luego empujaría ese compromiso a la producción.

En este punto, puede eliminar la columna original sin preocuparse por ningún tipo de tiempo de inactividad asociado con la migración en sí.

class RemoveBadColumnNames < ActiveRecord::Migration
  def up
    remove_column :table, :old_name_column_one
    remove_column :table, :old_name_column_two
  end

  def down
    add_column :table, :old_name_column_one, :string
    add_column :table, :old_name_column_two, :string
  end
end

Luego, empuje esta última migración a producción y ejecútela bundle exec rake db:migrateen segundo plano.

Me doy cuenta de que esto es un proceso un poco más complicado, pero prefiero hacerlo que tener problemas con mi migración de producción.

Paul Pettengill
fuente
2
Me gusta la idea detrás de esto, y haría +1 su respuesta, pero la actualización de datos tomaría mucho tiempo en ejecutarse ya que está pasando por rieles y haciendo una fila a la vez. La migración se ejecutaría mucho más rápido con sentencias sql sin formato para actualizar columnas con nombres correctos. Por ejemplo, en el primer script de migración de db, después de agregar los nombres de columna duplicados, execute "Update table_name set correct_name_column_one = old_name_column_one"
Gui Weinmann el
1
@ mr.ruh.roh ^ Totalmente de acuerdo, debería haber escrito eso en primer lugar. He editado para reflejar una sola declaración eficiente de SQL. Gracias por el control de cordura.
Paul Pettengill
2
¿Qué sucede con las entradas entre pasar a la nueva tabla y actualizar el código para usar la nueva tabla? ¿No podría tener datos potencialmente no migrados sobrantes?
Stefan Dorunga
1
Si bien esta es una respuesta "segura", creo que está incompleta. Mucha gente aquí dice que no hagas esto, ¿por qué? persistencia de datos. Y eso es válido. Probablemente la forma menos dolorosa de lograr el objetivo es crear los nuevos campos, llenarlos con los datos de las columnas antiguas, ajustar los controladores. Si desea eliminar las columnas antiguas, seguramente tendrá que editar las vistas. El costo de mantenerlos es espacio adicional de base de datos y un esfuerzo duplicado en el controlador. Las compensaciones son, por lo tanto, claras.
Jerome
18

Ejecute el siguiente comando para crear un archivo de migración:

rails g migration ChangeHasedPasswordToHashedPassword

Luego, en el archivo generado en la db/migratecarpeta, escriba rename_columnlo siguiente:

class ChangeOldCoulmnToNewColumn < ActiveRecord::Migration
  def change
     rename_column :table_name, :hased_password, :hashed_password
  end
end
Shoaib Malik
fuente
14

De API:

rename_column(table_name, column_name, new_column_name)

Cambia el nombre de una columna pero mantiene el tipo y el contenido sigue siendo el mismo.

super_p
fuente
12

Algunas versiones de Ruby on Rails son compatibles con el método arriba / abajo para la migración y si tiene un método arriba / abajo en su migración, entonces:

def up
    rename_column :table_name, :column_old_name, :column_new_name
end

def down
    rename_column :table_name, :column_new_name, :column_old_name
end

Si tiene el changemétodo en su migración, entonces:

def change
    rename_column :table_name, :column_old_name, :column_new_name
end

Para obtener más información, puede mover: Ruby on Rails - Migraciones o Migraciones de registros activos .

uma
fuente
11

Si su código no se comparte con otro, entonces la mejor opción es simplemente rake db:rollback editar el nombre de su columna en migración yrake db:migrate . Eso es

Y puede escribir otra migración para cambiar el nombre de la columna

 def change
    rename_column :table_name, :old_name, :new_name
  end

Eso es.

sunil
fuente
rake db:rollbackEs una gran sugerencia. Pero como dijiste, solo si la migración aún no se ha impulsado.
danielricecodes
9

Como opción alternativa, si no está casado con la idea de las migraciones, existe una joya convincente para ActiveRecord que se encargará de los cambios de nombre automáticamente, al estilo Datamapper. Todo lo que debe hacer es cambiar el nombre de la columna en su modelo (y asegúrese de poner Model.auto_upgrade! En la parte inferior de su model.rb) y viola! La base de datos se actualiza sobre la marcha.

https://github.com/DAddYE/mini_record

Nota: Necesitarás atacar db / schema.rb para evitar conflictos

Todavía en fases beta y obviamente no para todos, pero sigue siendo una opción convincente (actualmente lo estoy usando en dos aplicaciones de producción no triviales sin problemas)

Steven Garcia
fuente
8

Si necesita cambiar los nombres de columna, deberá crear un marcador de posición para evitar un error de nombre de columna duplicado . Aquí hay un ejemplo:

class SwitchColumns < ActiveRecord::Migration
  def change
    rename_column :column_name, :x, :holder
    rename_column :column_name, :y, :x
    rename_column :column_name, :holder, :y
  end
end
Abram
fuente
7

Si los datos actuales no son importantes para usted, puede eliminar su migración original usando:

rake db:migrate:down VERSION='YOUR MIGRATION FILE VERSION HERE'

Sin las comillas, realice cambios en la migración original y vuelva a ejecutar la migración:

rake db:migrate
dirtydexter
fuente
6

Simplemente cree una nueva migración y, en un bloque, úsela rename_columncomo se muestra a continuación.

rename_column :your_table_name, :hased_password, :hashed_password
Jon nieve
fuente
6

Para Ruby on Rails 4:

def change
    rename_column :table_name, :column_name_old, :column_name_new
end
Hardik Hardiya
fuente
5

Manualmente podemos usar el siguiente método:

Podemos editar la migración manualmente como:

  • Abierto app/db/migrate/xxxxxxxxx_migration_file.rb

  • Actualizar hased_passwordahashed_password

  • Ejecute el siguiente comando

    $> rake db:migrate:down VERSION=xxxxxxxxx

Luego eliminará su migración:

$> rake db:migrate:up VERSION=xxxxxxxxx

Agregará su migración con el cambio actualizado.

Sumit Munot
fuente
no será seguro ya que podría perder datos, si la columna ya está activa. pero puede hacerlo para una nueva columna y / o tabla.
Tejas Patel
5

Genere el archivo de migración:

rails g migration FixName

# Crea db / migrate / xxxxxxxxxx.rb

Edite la migración para hacer su voluntad.

class FixName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
vipin
fuente
5

Ejecutar rails g migration ChangesNameInUsers(o como quieras nombrarlo)

Abra el archivo de migración que se acaba de generar y agregue esta línea en el método (entre def changey end):

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

Guarde el archivo y ejecútelo rake db:migrateen la consola.

¡Mira tu schema.dbpara ver si el nombre realmente ha cambiado en la base de datos!

Espero que esto ayude :)

Maddie
fuente
5

Vamos a BESO . Todo lo que se necesita son tres simples pasos. Lo siguiente funciona para Rails 5.2 .

1) Crear una migración

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName- de esa manera queda perfectamente claro para los mantenedores de la base de código más adelante. (use un plural para el nombre de la tabla).

2. Edite la migración

# I prefer to explicitly write thearriba andabajomethods.

# ./db/migrate/20190114045137_rename_name_to_full_name_in_students.rb

class RenameNameToFullNameInStudents < ActiveRecord::Migration[5.2]
  def up
    # rename_column :table_name, :old_column, :new_column
    rename_column :students, :name, :full_name
  end

  def down
            # Note that the columns are reversed
    rename_column :students, :full_name, :name
  end
end

3. Ejecute sus migraciones

rake db:migrate

¡Y te vas a las carreras!

BKSpurgeon
fuente
4
$:  rails g migration RenameHashedPasswordColumn
invoke  active_record
      create    db/migrate/20160323054656_rename_hashed_password_column.rb

Abra ese archivo de migración y modifique ese archivo como se muestra a continuación (ingrese su original table_name)

class  RenameHashedPasswordColumn < ActiveRecord::Migration
  def change
    rename_column :table_name, :hased_password, :hashed_password
  end
end
Prabhakar Undurthi
fuente
4
 def change
    rename_column :table_name, :old_column_name, :new_column_name
  end
Apoorv
fuente
3

Generar una migración de Ruby on Rails :

$:> rails g migration Fixcolumnname

Inserte el código en el archivo de migración (XXXXXfixcolumnname.rb) :

class Fixcolumnname < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
vipin
fuente
2

Abra su consola Ruby on Rails e ingrese:

ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column
Rinold Simon
fuente
2

Tienes dos formas de hacer esto:

  1. En este tipo, ejecuta automáticamente el código inverso al retroceder.

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
  2. Para este tipo, ejecuta el método up cuando rake db:migratey ejecuta el método down cuando rake db:rollback:

    def self.up
      rename_column :table_name, :old_column_name, :new_column_name
    end
    
    def self.down
      rename_column :table_name,:new_column_name,:old_column_name
    end
Sarwan Kumar
fuente
2

Estoy en rails 5.2, e intento cambiar el nombre de una columna en un dispositivo ideado.

el rename_columnbit funcionó para mí, pero el singular :table_namearrojó un error "No se encontró la tabla de usuario". Plural funcionó para mí.

rails g RenameAgentinUser

Luego cambie el archivo de migración a esto:

rename_column :users, :agent?, :agent

Donde: agente? es el antiguo nombre de columna.

tumba
fuente
0

Actualización : un primo cercano de create_table es change_table, que se usa para cambiar las tablas existentes. Se usa de manera similar a create_table pero el objeto cedido al bloque conoce más trucos. Por ejemplo:

class ChangeBadColumnNames < ActiveRecord::Migration
  def change
    change_table :your_table_name do |t|
      t.rename :old_column_name, :new_column_name
    end
  end
end

Esta forma es más eficiente si lo hacemos con otros métodos alternos como: eliminar / agregar índice / eliminar índice / agregar columna, por ejemplo, podemos hacer más cosas como:

# Rename
t.rename :old_column_name, :new_column_name
# Add column
t.string :new_column
# Remove column
t.remove :removing_column
# Index column
t.index :indexing_column
#...
Hieu Pham
fuente
0

Solo genera la migración usando el comando

rails g migration rename_hased_password

Después de eso, edite la migración y agregue la siguiente línea en el método de cambio

rename_column :table, :hased_password, :hashed_password

Esto debería funcionar.

Ratnam Yadav
fuente
0

Rails 5 cambios de migración

p.ej:

rails modelo g Student student_name: string age: integer

si quieres cambiar la columna student_name como nombre

Nota: - si no ejecuta rails db: migrate

Puedes hacer los siguientes pasos

rieles d modelo Alumno nombre_alumno: edad de la cadena: entero

Esto eliminará el archivo de migración generado. Ahora puede corregir el nombre de su columna

rieles modelo g Nombre del alumno: edad de la cadena: entero

Si migró (rails db: migrate), siga las opciones para cambiar el nombre de la columna

rieles g migración RemoveStudentNameFromStudent student_name: string

rails g migración AddNameToStudent nombre: cadena

prasanthrubyist
fuente
¿No debería ser: rails g migration RemoveStudentNameFromStudentS student_name:string(los estudiantes son plurales)?
BKSpurgeon
También esto es peligroso: la columna no se renombra, sino que se elimina por completo y luego se vuelve a leer. ¿Qué pasará con los datos? Esto puede no ser lo que el usuario querrá.
BKSpurgeon