Schienenmigration für Änderungsspalte

327

Wir haben eine script/generate migration add_fieldname_to_tablename fieldname:datatypeSyntax zum Hinzufügen neuer Spalten zu einem Modell.

Haben wir in derselben Zeile ein Skript / Generieren zum Ändern des Datentyps einer Spalte? Oder sollte ich SQL direkt in meine Vanille-Migration schreiben?

Ich möchte eine Spalte von datetimenach ändern date.

papdel
quelle

Antworten:

547

Ich denke das sollte funktionieren.

change_column :table_name, :column_name, :date
Alex Korban
quelle
13
@b_ayan: Soweit ich weiß, sind die einzigen magischen Wörter in Migrationsnamen "Hinzufügen" und "Entfernen".
Alex Korban
1
Eine Art Schienen noob hier, aber ... Ich verstehe die Antwort, aber nicht die Kommentare zu dieser Antwort. Klarstellungen geschätzt :)
Alan H.
7
Wenn Sie eine Migration erstellen, geben Sie ihr einen Namen (z. B. add_fieldname_to_tablename in der obigen Frage). Wenn es mit "Hinzufügen" oder "Entfernen" beginnt, wird die Migration automatisch mit Code zum Hinzufügen oder Entfernen von Spalten gefüllt, sodass Sie diesen Code nicht selbst schreiben müssen.
Alex Korban
5
Beachten Sie auch, dass Sie die übliche changeAktion durch separate upund downAktionen ersetzen sollten , da dies change_columneine irreversible Migration ist und einen Fehler auslöst, falls Sie ein Rollback durchführen müssen.
DaveStephens
1
@QPaysTaxes up sollte enthalten, was Sie von und nach ändern möchten, und down sollte enthalten, wie diese Änderung rückgängig gemacht werden kann.
DaveStephens
98

Sie können auch einen Block verwenden, wenn Sie mehrere Spalten innerhalb einer Tabelle ändern müssen.

Beispiel:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

Weitere Informationen finden Sie in der API-Dokumentation zur Table-Klasse .

John
quelle
88

Mir ist nicht bekannt, ob Sie eine Migration über die Befehlszeile erstellen können, um all dies zu tun, aber Sie können eine neue Migration erstellen und dann die Migration bearbeiten, um diese Aufgaben auszuführen.

Wenn Tabellenname der Name Ihrer Tabelle ist, Feldname der Name Ihres Feldes ist und Sie von Datum zu Datum wechseln möchten, können Sie dazu eine Migration schreiben.

Sie können eine neue Migration erstellen mit:

rails g migration change_data_type_for_fieldname

Bearbeiten Sie dann die Migration, um change_table zu verwenden:

class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

Führen Sie dann die Migration aus:

rake db:migrate
Ryan
quelle
32

Wie ich aus den vorherigen Antworten herausgefunden habe, sind drei Schritte erforderlich, um den Typ einer Spalte zu ändern:

Schritt 1:

Generieren Sie eine neue Migrationsdatei mit diesem Code:

rails g migration sample_name_change_column_type

Schritt 2:

Gehen Sie zum /db/migrateOrdner und bearbeiten Sie die von Ihnen erstellte Migrationsdatei. Es gibt zwei verschiedene Lösungen.

  1. def change
        change_column(:table_name, :column_name, :new_type)
    end

2.

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end

Schritt 3:

Vergessen Sie nicht, diesen Befehl auszuführen:

rake db:migrate

Ich habe diese Lösung für Rails 4 getestet und sie funktioniert gut.

Aboozar Rajabi
quelle
1
In Schritt 2 wird der erste nach dem Ausführen von Rake DB: Rollback fehlschlagen. Ich empfehle Ihnen, den zweiten zu überprüfen
Feuda
Gibt es eine Rails-Konvention, die es ermöglicht, dass mehr oder weniger alles erledigt wird, wenn die Migrationsdatei generiert wird, ohne darauf zuzugreifen und sie dann zu bearbeiten?
BKSpurgeon
@ BKSpurgeon Ja, überprüfen Sie die Dokumentation hier: edgeguides.rubyonrails.org/active_record_migrations.html
Aboozar Rajabi
12

Mit Schienen 5

Von Rails Guides :

Wenn Sie möchten, dass eine Migration etwas bewirkt, das Active Record nicht rückgängig machen kann, können Sie Folgendes verwenden reversible:

class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      change_table :tablename do |t|
        dir.up   { t.change :fieldname, :date }
        dir.down { t.change :fieldname, :datetime }
      end
    end
  end
end
Herr Tao
quelle
8

Generieren Sie einfach eine Migration:

rails g migration change_column_to_new_from_table_name

Aktualisieren Sie die Migration wie folgt:

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end

und schlussendlich

rake db:migrate
Vivek Sharma
quelle
2

Eine andere Möglichkeit, den Datentyp mithilfe der Migration zu ändern

Schritt 1: Sie müssen den Feldnamen des fehlerhaften Datentyps mithilfe der Migration entfernen

Ex:

rails g migration RemoveFieldNameFromTableName field_name:data_type

Vergessen Sie hier nicht, den Datentyp für Ihr Feld anzugeben

Schritt 2: Jetzt können Sie ein Feld mit dem richtigen Datentyp hinzufügen

Ex:

rails g migration AddFieldNameToTableName field_name:data_type

Das war's, jetzt wird Ihre Tabelle mit dem richtigen Datentypfeld hinzugefügt. Happy Ruby Coding !!

Prasanthrubyist
quelle
1

Dies alles setzt voraus, dass der Datentyp der Spalte eine implizite Konvertierung für alle vorhandenen Daten aufweist. Ich bin auf mehrere Situationen gestoßen, in denen die vorhandenen Daten, sagen Stringwir, implizit in den neuen Datentyp konvertiert werden können Date.

In dieser Situation ist es hilfreich zu wissen, dass Sie Migrationen mit Datenkonvertierungen erstellen können. Persönlich mag ich es, diese in meine Modelldatei aufzunehmen und sie dann zu entfernen, nachdem alle Datenbankschemas migriert wurden und stabil sind.

/app/models/table.rb
  ...
  def string_to_date
    update(new_date_field: date_field.to_date)
  end

  def date_to_string
    update(old_date_field: date_field.to_s)
  end
  ...
    def up
        # Add column to store converted data
        add_column :table_name, :new_date_field, :date
        # Update the all resources
        Table.all.each(&:string_to_date)
        # Remove old column
        remove_column :table_name, :date_field
        # Rename new column
        rename_column :table_name, :new_date_field, :date_field
    end

    # Reversed steps does allow for migration rollback
    def down
        add_column :table_name, :old_date_field, :string
        Table.all.each(&:date_to_string)
        remove_column :table_name, :date_field
        rename_column :table_name, :old_date_field, :date_field
    end
Sebastian Scholl
quelle
0

So vervollständigen Sie die Antworten beim Bearbeiten des Standardwerts :

In Ihrer Rails-Konsole:

rails g migration MigrationName

In der Migration:

  def change
    change_column :tables, :field_name, :field_type, default: value
  end

Wird aussehen wie :

  def change
    change_column :members, :approved, :boolean, default: true
  end
Gregdebrick
quelle