Wie kann ich eine Datenbankspalte in einer Ruby on Rails-Migration umbenennen?

1451

Ich habe fälschlicherweise eine Spalte hased_passwordanstelle von benannt hashed_password.

Wie aktualisiere ich das Datenbankschema mithilfe der Migration, um diese Spalte umzubenennen?

user1994764
quelle

Antworten:

2308
rename_column :table, :old_column, :new_column

Möglicherweise möchten Sie dazu eine separate Migration erstellen. (Umbenennen FixColumnNamewie du willst.):

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

Bearbeiten Sie dann die Migration, um Ihren Willen zu erfüllen:

# 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

Für Rails 3.1 verwenden Sie:

Während die Methoden upund downweiterhin gelten, erhält Rails 3.1 eine changeMethode, die "weiß, wie Sie Ihre Datenbank migrieren und umkehren, wenn die Migration zurückgesetzt wird, ohne dass eine separate Down-Methode geschrieben werden muss".

Weitere Informationen finden Sie unter " Aktive Datensatzmigrationen ".

rails g migration FixColumnName

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

Wenn Sie zufällig eine ganze Reihe von Spalten umbenennen müssen oder etwas, bei dem der Tabellenname immer wieder wiederholt werden müsste:

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

Sie könnten verwenden change_table, um die Dinge ein wenig ordentlicher zu halten:

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

Dann db:migratewie gewohnt oder wie auch immer Sie Ihrem Geschäft nachgehen.


Für Schienen 4:

Beim Erstellen einer MigrationSpalte zum Umbenennen einer Spalte generiert Rails 4 changeanstelle von upund downwie im obigen Abschnitt erwähnt eine Methode . Die generierte changeMethode ist:

$ > rails g migration ChangeColumnName

Dadurch wird eine Migrationsdatei erstellt, die der folgenden ähnelt:

class ChangeColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
nowk
quelle
24
self.down sollte immer das Gegenteil von self.up sein, daher wird "wenn Sie etwas anderes brauchen oder tun oder nichts tun" nicht wirklich empfohlen. Tun Sie einfach: rename_column: table_name ,: new_column ,: old_column
Luke Griffiths
3
Während es üblich ist, das, was Sie getan haben, rückgängig zu machen, self.upwürde ich nicht sagen self.down"sollte immer das Gegenteil sein". In hängt vom Kontext Ihrer Migration ab. Nur das "Gegenteil" zu setzen, ist möglicherweise nicht die "richtige" Abwärtsmigration.
Nowk
23
In Rails 3.1 können Sie ersetzen def self.upund def self.downmit def changeund es wird wissen , wie ein Rollback.
Turadg
2
Turadg - * es wird die meiste Zeit wissen, wie man zurückrollt. Ich finde das changeVerfahren nicht die volle Beweis ist, so ist in der Regel verwendet werden upund downfür komplexe Migrationen Methoden.
JellyFishBoy
6
Entfernt das Umbenennen den Index?
Sung Cho
68

Meiner Meinung nach ist es in diesem Fall besser rake db:rollback, die Migration zu verwenden , zu bearbeiten und erneut auszuführen rake db:migrate.

Wenn Sie jedoch Daten in der Spalte haben, die Sie nicht verlieren möchten, verwenden Sie rename_column.

elf.xf
quelle
34
Selbst in einem "Team von einem" ist die Verwaltung bearbeiteter Migrationen ein großes Problem, wenn mehrere Instanzen Ihrer App ausgeführt werden, beispielsweise in verschiedenen Umgebungen oder auf mehreren Computern usw. Ich bearbeite eine Migration nur, wenn ich sie gerade erstellt und festgestellt habe, dass sie falsch ist, und habe sie noch nirgendwo anders buchstäblich ausgeführt.
Yetanotherjosh
1
Danach musste ich den Server neu starten.
Muhammad Hewedy
7
Diese Technik sollte nur in Situationen verwendet werden, in denen Ihre Änderungen noch nicht mit Ihrem Produktionszweig zusammengeführt wurden und andere nicht von der Datenpersistenz abhängig sind. In fast allen Produktionsumständen ist dies NICHT die bevorzugte Methode.
Collin Graves
4
Mach niemals solche Dinge.
New2Cpp
4
Ich möchte meinem Team sagen: "Migrationen sind kostenlos" Die Kosten für die Bearbeitung einer Migration, die in die Wildnis entlassen wurde, sind hoch: Ich habe einmal ein paar Stunden lang herausgefunden, warum mein Code nicht funktioniert, bevor ich ein anderes Teammitglied erkannt habe war zurückgegangen und hatte eine Migration bearbeitet, die ich bereits ausgeführt hatte. Bearbeiten Sie also keine vorhandene Migration, sondern verwenden Sie eine neue, um das Schema zu ändern, da ... ... 'Migrationen kostenlos sind!' (Es ist nicht unbedingt wahr, aber es macht den Punkt)
TerryS
31

Wenn die Spalte bereits mit Daten gefüllt ist und sich in der Produktion befindet, würde ich einen schrittweisen Ansatz empfehlen, um Ausfallzeiten in der Produktion während des Wartens auf die Migrationen zu vermeiden.

Zuerst würde ich eine Datenbankmigration erstellen, um Spalten mit den neuen Namen hinzuzufügen und sie mit den Werten aus dem alten Spaltennamen zu füllen.

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

Dann würde ich genau diese Änderung begehen und die Änderung in die Produktion bringen.

git commit -m 'adding columns with correct name'

Sobald das Commit in die Produktion verschoben wurde, würde ich laufen.

Production $ bundle exec rake db:migrate

Dann würde ich alle Ansichten / Controller aktualisieren, die den alten Spaltennamen auf den neuen Spaltennamen verweisen. Führen Sie meine Testsuite durch und übernehmen Sie nur diese Änderungen. (Nachdem Sie sichergestellt haben, dass es lokal funktioniert und alle Tests zuerst bestanden haben!)

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

Dann würde ich dieses Engagement für die Produktion vorantreiben.

Zu diesem Zeitpunkt können Sie die ursprüngliche Spalte entfernen, ohne sich Gedanken über Ausfallzeiten machen zu müssen, die mit der Migration selbst verbunden sind.

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

Schieben Sie dann diese neueste Migration in die Produktion und führen Sie sie bundle exec rake db:migrateim Hintergrund aus.

Mir ist klar, dass dies ein bisschen mehr mit einem Prozess zu tun hat, aber ich würde dies lieber tun, als Probleme mit meiner Produktionsmigration zu haben.

Paul Pettengill
quelle
2
Ich mag das Denken dahinter, und ich würde Ihre Antwort +1 geben, aber diese Datenaktualisierung würde sehr lange dauern, da sie durch Schienen geht und eine Zeile nach der anderen ausführt. Die Migration würde mit SQL-Rohanweisungen viel schneller ausgeführt, um korrekt benannte Spalten zu aktualisieren. Zum Beispiel im ersten DB-Migrationsskript nach dem Hinzufügen der doppelten Spaltennamen execute "Update table_name set correct_name_column_one = old_name_column_one"
Gui Weinmann
1
@ mr.ruh.roh ^ Stimme voll und ganz zu, hätte das an erster Stelle schreiben sollen. Ich habe bearbeitet, um eine einzelne effiziente SQL-Anweisung wiederzugeben. Vielen Dank für die Überprüfung der Gesundheit.
Paul Pettengill
2
Was passiert mit Einträgen zwischen dem Verschieben in die neue Tabelle und dem Aktualisieren des Codes zur Verwendung der neuen Tabelle? Könnten Sie nicht möglicherweise nicht migrierte Daten übrig haben?
Stefan Dorunga
1
Obwohl dies eine "sichere" Antwort ist, halte ich sie für unvollständig. Viele Leute hier sagen, tu das nicht - warum? Persistenz von Daten. Und das ist gültig. Der wahrscheinlich am wenigsten schmerzhafte Weg, um das Ziel zu erreichen, besteht darin, die neuen Felder zu erstellen, sie mit den Daten aus den alten Spalten zu füllen und die Controller anzupassen. Wenn Sie die alten Spalten löschen möchten, müssen Sie die Ansichten auf jeden Fall bearbeiten. Die Kosten für die Aufbewahrung sind zusätzlicher Datenbankspeicher und doppelter Aufwand im Controller. Die Kompromisse sind somit klar.
Jerome
18

Führen Sie den folgenden Befehl aus, um eine Migrationsdatei zu erstellen:

rails g migration ChangeHasedPasswordToHashedPassword

db/migrateSchreiben Sie dann in die im Ordner generierte Datei rename_columnwie folgt:

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

Von der API:

rename_column(table_name, column_name, new_column_name)

Es benennt eine Spalte um, behält jedoch den Typ und den Inhalt bei.

super_p
quelle
12

Einige Versionen von Ruby on Rails unterstützen die Up / Down-Methode für die Migration. Wenn Ihre Migration eine Up / Down-Methode enthält, gilt Folgendes:

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

Wenn Sie die changeMethode in Ihrer Migration haben, dann:

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

Weitere Informationen können Sie verschieben: Ruby on Rails - Migrationen oder Active Record-Migrationen .

uma
quelle
11

Wenn Ihr Code nicht mit anderen geteilt wird, ist es am besten, wenn Sie rake db:rollback Ihren Spaltennamen in der Migration und bearbeitenrake db:migrate . Das ist es

Sie können eine weitere Migration schreiben, um die Spalte umzubenennen

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

Das ist es.

sunil
quelle
rake db:rollbackist ein toller Vorschlag. Aber wie Sie sagten, nur wenn die Migration noch nicht vorangetrieben wurde.
Danielricecodes
9

Als alternative Option gibt es für ActiveRecord ein überzeugendes Juwel, das die Namensänderungen automatisch im Datamapper-Stil für Sie übernimmt, wenn Sie nicht mit der Idee von Migrationen verheiratet sind. Alles, was Sie tun, ist, den Spaltennamen in Ihrem Modell zu ändern (und sicherzustellen, dass Sie Model.auto_upgrade! Am unteren Rand Ihrer model.rb!) Und viola! Die Datenbank wird im laufenden Betrieb aktualisiert.

https://github.com/DAddYE/mini_record

Hinweis: Sie müssen db / schema.rb nuken , um Konflikte zu vermeiden

Noch in der Beta-Phase und natürlich nicht für jedermann, aber immer noch eine überzeugende Wahl (ich verwende es derzeit in zwei nicht trivialen Produktions-Apps ohne Probleme).

Steven Garcia
quelle
8

Wenn Sie den Spaltennamen wechseln müssen, müssen Sie einen Platzhalter erstellen, um einen doppelten Spaltennamenfehler zu vermeiden . Hier ist ein Beispiel:

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
quelle
7

Wenn die vorliegenden Daten für Sie nicht wichtig sind, können Sie Ihre ursprüngliche Migration einfach mit folgenden Schritten beenden:

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

Nehmen Sie ohne die Anführungszeichen Änderungen an der ursprünglichen Migration vor und führen Sie die Aufwärtsmigration erneut aus durch:

rake db:migrate
Dirtydexter
quelle
6

Erstellen Sie einfach eine neue Migration und verwenden Sie sie in einem Block rename_columnwie folgt.

rename_column :your_table_name, :hased_password, :hashed_password
Jon Schnee
quelle
6

Für Ruby on Rails 4:

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

Manuell können wir die folgende Methode verwenden:

Wir können die Migration manuell bearbeiten wie folgt:

  • Öffnen app/db/migrate/xxxxxxxxx_migration_file.rb

  • Update hased_passwordaufhashed_password

  • Führen Sie den folgenden Befehl aus

    $> rake db:migrate:down VERSION=xxxxxxxxx

Dann wird Ihre Migration entfernt:

$> rake db:migrate:up VERSION=xxxxxxxxx

Es wird Ihre Migration mit der aktualisierten Änderung hinzufügen.

Sumit Munot
quelle
Es ist nicht sicher, da Sie möglicherweise Daten verlieren - wenn die Spalte bereits aktiv ist. kann aber für neue Spalte und / oder Tabelle tun.
Tejas Patel
5

Generieren Sie die Migrationsdatei:

rails g migration FixName

# Erstellt db / migrate / xxxxxxxxxx.rb

Bearbeiten Sie die Migration nach Ihren Wünschen.

class FixName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
Vipin
quelle
5

Lauf rails g migration ChangesNameInUsers (oder wie auch immer Sie es nennen möchten)

Öffnen Sie die soeben generierte Migrationsdatei und fügen Sie diese Zeile in die Methode ein (zwischen def changeund end):

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

Speichern Sie die Datei und führen Sie sie rake db:migratein der Konsole aus

Überprüfen Sie Ihre schema.db, um festzustellen, ob sich der Name in der Datenbank tatsächlich geändert hat!

Hoffe das hilft :)

Maddie
quelle
5

Lass uns küssen . Alles was es braucht sind drei einfache Schritte. Das Folgende funktioniert für Rails 5.2 .

1. Erstellen Sie eine Migration

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName- Auf diese Weise ist es den Betreuern der Codebasis später völlig klar. (Verwenden Sie einen Plural für den Tabellennamen).

2. Bearbeiten Sie die Migration

# I prefer to explicitly write therauf andruntermethods.

# ./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. Führen Sie Ihre Migrationen aus

rake db:migrate

Und du bist auf dem Weg zu den Rennen!

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

Öffnen Sie diese Migrationsdatei und ändern Sie diese Datei wie folgt (Geben Sie Ihr Original ein table_name)

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

Generieren Sie eine Ruby on Rails-Migration :

$:> rails g migration Fixcolumnname

Fügen Sie Code in die Migrationsdatei ein (XXXXXfixcolumnname.rb) :

class Fixcolumnname < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
Vipin
quelle
2

Öffnen Sie Ihre Ruby on Rails-Konsole und geben Sie Folgendes ein:

ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column
rinold simon
quelle
2

Sie haben zwei Möglichkeiten, dies zu tun:

  1. Bei diesem Typ wird beim Rollback automatisch der umgekehrte Code ausgeführt.

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
  2. Bei diesem Typ wird die Aufwärtsmethode ausgeführt, wenn rake db:migrateund die Abwärtsmethode ausgeführt, wenn 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
quelle
2

Ich bin auf Rails 5.2 und versuche, eine Spalte auf einem Entwicklerbenutzer umzubenennen.

Das rename_columnBit hat bei mir funktioniert, aber der Singular hat den :table_nameFehler "Benutzertabelle nicht gefunden" ausgegeben. Plural hat für mich gearbeitet.

rails g RenameAgentinUser

Ändern Sie dann die Migrationsdatei in folgende Datei:

rename_column :users, :agent?, :agent

Wo: Agent? ist der alte Spaltenname.

Grab
quelle
0

Update - Ein enger Verwandter von create_table ist change_table, mit dem vorhandene Tabellen geändert werden. Es wird auf ähnliche Weise wie create_table verwendet, aber das dem Block übergebene Objekt kennt mehr Tricks. Zum Beispiel:

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

Diese Methode ist effizienter, wenn wir andere Änderungsmethoden verwenden, z. B.: Index entfernen / Index hinzufügen / Index entfernen / Spalte hinzufügen, z.

# 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
quelle
0

Generieren Sie einfach die Migration mit dem Befehl

rails g migration rename_hased_password

Nach dieser Bearbeitung der Migration fügen Sie die folgende Zeile in der Änderungsmethode hinzu

rename_column :table, :hased_password, :hashed_password

Dies sollte den Trick tun.

Ratnam Yadav
quelle
0

Rails 5-Migrationsänderungen

z.B:

Schienen g Modell Student student_name: string age: integer

Wenn Sie die Spalte student_name als Namen ändern möchten

Hinweis: - Wenn Sie keine Rails ausführen db: migrate

Sie können die folgenden Schritte ausführen

Schienen d Modell Student student_name: string age: integer

Dadurch wird die generierte Migrationsdatei entfernt. Jetzt können Sie Ihren Spaltennamen korrigieren

Schienen g Modell Schülername: Zeichenfolge Alter: Ganzzahl

Wenn Sie migriert haben (Rails DB: Migrieren), gehen Sie wie folgt vor, um den Spaltennamen zu ändern

Schienen g Migration RemoveStudentNameFromStudent student_name: string

Schienen g Migration AddNameToStudent Name: Zeichenfolge

Prasanthrubyist
quelle
Sollte es nicht sein: rails g migration RemoveStudentNameFromStudentS student_name:string(die Schüler sind Plural)?
BKSpurgeon
Auch das ist gefährlich: Die Spalte wird nicht umbenannt, sondern vollständig entfernt und dann neu gelesen. Was wird mit den Daten passieren? Dies ist möglicherweise nicht das, was der Benutzer möchte.
BKSpurgeon