2009-05-11 18 views
32

Ich versuche, eine Spalte in meiner Rails-App zu konvertieren, für Argumente willen tun wir so tun, dass ich versuche, die age Spalte in meiner users Tabelle in eine Zeichenfolgendarstellung statt ein int zu ändern.Can Rails Migrationen werden zum Konvertieren von Daten verwendet?

In meiner Migration Ich habe dies;

def.self up 
    add_column :users, :age_text, :string 

    users = User.find(:all) 

    users.each do |u| 
     u.age_text = convert_to_text(u.age) 
     u.save 
    end 
end 

def self.convert_to_text(number) 
    #code here to convert 1 to 'one' etc 
end 

Aber es scheint nicht zu funktionieren, ist das, was ich hier versuche, sogar mit Migrationen möglich?

Antwort

56

Was Sie versuchen zu tun ist möglich, und ich würde sagen, das Richtige zu tun.

Sie müssen jedoch die Spalteninformationen für die Modellklassen, die Sie bei der Migration aktualisieren, neu laden, damit Rails die neuen Spalten kennt. Versuchen Sie folgendes:

def.self up 
    add_column :users, :age_text, :string 

    User.reset_column_information 

    users = User.find(:all) 

    users.each do |u| 
     u.age_text = convert_to_text(u.age) 
     u.save 
    end 
end 

Auf einem separaten Hinweis, bitte beachten Sie, dass, wenn Ihre Tabelle groß ist, tut Updates eins nach dem anderen wird eine looong Zeit in Anspruch nehmen .. Seien Sie vorsichtig damit.

+2

Was wäre ein besserer Weg? – Kirschstein

+0

Hängt davon ab, was Sie tun möchten. Wenn es ein einfaches Update ist, können Sie einfach einen SQL-Befehl mit der execute-Methode ausführen (führen Sie 'update user set colA = 1' aus). Sei wieder vorsichtig. Wenn Sie 10k Benutzer in der Benutzertabelle haben, wird das Durchlaufen jedes einzelnen mit der obigen Migration sehr lange dauern. –

+1

Manchmal müssen Sie auch dazu User.connection.schema_cache.clear! – hrdwdmrbl

38

Da ich neu hier bin, kann ich nicht auf die obige Bemerkung so werde ich meine eigene Antwort hinzufügen.

ALLGEMEINEN Daten in Migrationen Manipulation ist eine schlechte Idee. Migrationen mit direktem Modellzugriff können hängenbleiben, wenn sich die Modelllogik ändert.

Imagine in Ihrer zweiten Migration haben Sie eine neue Spalte hinzugefügt. Sie möchten diese Spalte mit neuen Daten versehen.

Nehmen wir an, dass Sie einige Wochen später dem Modell eine neue Validierung hinzufügen - eine Validierung, die auf einem Feld ausgeführt wird, das in Ihrer zweiten Migration noch nicht existiert. Wenn Sie jemals die Datenbank von Migration 0 erstellen würden, hätten Sie einige Probleme.

Ich empfehle dringend, Migrationen zu verwenden, um Spalten und andere Mittel zum Verwalten von Datenbankdaten zu ändern, insbesondere wenn Sie in die Produktion wechseln.

+0

Hmm, sehr guter Punkt. Wie gehen Sie bei der Konvertierung von Daten vor? – Kirschstein

+1

Ich mache eine Rechenaufgabe. Es ist einfacher und auch einfacher zu testen, auch wenn ich es wegwerfe, nachdem ich es benutzt habe. –

+3

Gibt es eine Möglichkeit sicherzustellen, dass Ihre Rake-Aufgaben in der richtigen Reihenfolge zusammen mit Migrationen ausgeführt werden? Was passiert, wenn eine nach diesem Vorgang vorgenommene Migration die veraltete Spalte vor dem Ausführen der Rake-Task abbricht? – Kirschstein

0

Ich würde sagen, wenn Sie die importierten Daten beim Zurücksetzen der Migrationsversion "rückgängig machen" können, ist es angemessen, Importe in die Migration zu übernehmen.

Zum Beispiel habe ich eine Migration, die eine Menge von Nachschlagetabellen und anderen Metadaten erstellt. Die Daten für diese Tabellen werden während dieser Phase ausgefüllt. Wenn sich die Daten für diese Nachschlagetabellen ändern, erstelle ich neue YAML-Dateien, die die Metadaten speichern, und lade diese Dateien bei nachfolgenden Migrationen (und entmarke diese YAMLS, wobei die vorherige YAML-Datei beim Zurücksetzen einer Migrationsversion erneut geladen wird). Das ist ziemlich sauber. Ich habe Dateien (in verschiedenen gut definierten Ordnern in meinem Fall) mit diesen Dateien:

002_setup_meta_data.rb 
002_meta_data.yaml 


007_change_meta_data.rb 
007_meta_data.yaml 

Wenn Sie „Produktion“ Daten von einem anderen System in transaktionale (nicht statisch) Tabellen importieren, dann würde ich sagen, Verwenden von Migrationen ist nicht angemessen. Dann folgte ich Brian Hogans Rat, Rake-Aufgaben zu verwenden. Hier

4

ist ein Beispiel Migration Ich lief Daten zu konvertieren. Sie können es einfach konvertieren, um Ganzzahlen anstelle von Zeichenfolgen zu verwenden. Die Konvertierung in SQL ist viel schneller als das Laden jeder Zeile in Rails.

class ConvertCommentTextToText < ActiveRecord::Migration 
    def up 
    add_column :comments, :text_tmp, :text 
    # copy text column 
    execute <<-SQL 
     update comments set text_tmp = text 
    SQL 
    remove_column :comments, :text 
    rename_column :comments, :text_tmp, :text 
    end 

    def down 
    add_column :comments, :text_tmp, :string 
    # copy text column 
    execute <<-SQL 
     update comments set text_tmp = text 
    SQL 
    remove_column :comments, :text 
    rename_column :comments, :text_tmp, :text 
    end 

end 

Und um es zu testen:

rake db:migrate 
rake db:rollback 
rake db:migrate 
Verwandte Themen