2015-09-30 5 views
7

stringのフィールドをintegerに変換し、代わりにenumを使用する必要があります。 データを失うことなくこれを行う最善の方法は何ですか?列4のデータ型を文字列から整数に戻し、データを保持する(ポストグル)

これは、現在の移行です:

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

     t.timestamps null: false 
    end 
    end 
end 

それから私はそうのようなフィールドの種類を変更します。

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

とモデルファイルを更新します。

/app/models/system.rb

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

どのように私は古いデータを更新することができますか?あなたは2移行でそれを行うことができます

答えて

7

いくつかの調査の後、私はこれが適切な解決策であることを発見しました。

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:あなたはタイプを変更する前に、デフォルト値を削除する必要がありますいくつかのケースでは 。 ここにロールバックされたバージョンがあります。

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

1.現在のoperation列の名前を変更し、新しいに古い列からneccessaryタイプで

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

2.移動値を新たに追加し、古い列を削除手順

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 

それはneccessaryだ場合は書き込みロールバックコードを忘れてはいけない

+0

この移行は、破損し、すべてのデータは、あなたが文字列の '.to_i'呼び出すときので、あなたは常に期待通りのコードの0 次の作品がうまくいくでしょうします。しかし、それは最善の解決策ではありません。 'sys.operation = System.operations [sys.operation_str]' – Pav31

関連する問題