2015-09-30 3 views
7

erhalten. Was ist der beste Weg, dies zu tun, ohne Daten zu verlieren?Rails 4 Migration auf Spalten Datentyp aus Zeichenfolge zu ändern, um zu integer und ich brauche <code>string</code> Felder in <code>integer</code> und <code>enum</code> stattdessen verwenden, um zurück zu konvertieren Daten (Postgres)

Dies ist aktuelle Migration:

class CreateSystems < ActiveRecord::Migration 
    def change 
    create_table :systems do |t| 
     t.string :operation 
     t.string :status 

     t.timestamps null: false 
    end 
    end 
end 

Dann Art der Felder wie so ich ändern:

class ChangeColumnsForSystems < ActiveRecord::Migration 
    def change 
    change_column :systems, :operation, :integer 
    change_column :systems, :status, :integer 
    end 
end 

und Update-Modell-Datei.

/app/models/system.rb

... 
enum operation { start: 0, stop: 1 } 
enum status { init: 0, working: 1, complete: 2 } 
... 

Wie ich alte Daten aktualisieren?

Antwort

7

Nach einigen Recherchen fand ich, dass dies eine richtige Lösung ist.

class ChangeColumnsForSystems < ActiveRecord::Migration 
    def change 
    change_column :systems, :operation, "integer USING (CASE operation WHEN 'start' THEN '0'::integer ELSE '1'::integer END)", null: false 
    change_column :systems, :status, "integer USING (CASE status WHEN 'init' THEN '0'::integer WHEN 'working' THEN '1'::integer ELSE '2'::integer END)", null: false 
    end 
end 

UPDATE: In einigen Fällen müssen Sie Standardwert vor dem Wechsel Typ entfernen. Hier ist die Version mit Rollback.

class ChangeColumnsForSystems < ActiveRecord::Migration 
    def up 
    change_column_default :systems, :status, nil 
    change_column :systems, :operation, "integer USING (CASE operation WHEN 'start' THEN '0'::integer ELSE '1'::integer END)", null: false 
    change_column :systems, :status, "integer USING (CASE status WHEN 'init' THEN '0'::integer WHEN 'working' THEN '1'::integer ELSE '2'::integer END)", null: false, default: 0 
    end 

    def down 
    change_column_default :systems, :status, nil 
    change_column :systems, :operation, "varchar USING (CASE operation WHEN '0' THEN 'start'::varchar ELSE 'stop'::varchar END)", null: false 
    change_column :systems, :status, "varchar USING (CASE status WHEN '0' THEN 'init'::varchar WHEN '1' THEN 'working'::varchar ELSE 'complete'::varchar END)", null: false, default: 'init' 
    end 
end 
2

Sie können es Migration in 2 do Schritte

1. aktuellen operation Spalte umbenennen und neu hinzufügen, mit notwendigen Typ

def up 
    rename_column :systems, :operation, :operation_str 
    add_column :systems, :operation, ... # your options 
end 

2. Bewegen Sie Werte aus alten Spalte, um neue und alte Spalte fallen

def up 
    System.all.each do |sys| 
     sys.operation = sys.operation_str.to_i # replace it with your converter 
    end 
    remove_column :systems, :operation 
end 

schreiben Rollback-Code nicht vergessen, wenn es

notwendig ist
+0

alle Daten Diese Migration wird beschädigt, weil, wenn Sie anrufen '.to_i' an einer Schnur, werden Sie immer 0. nächste Stück Code erhalten wird wie erwartet. Es ist jedoch nicht die beste Lösung 'sys.operation = System.operations [sys.operation_str]' – Pav31