2015-09-30 51 views
7

我需要將string字段轉換爲integer並使用enum來代替。 在不丟失數據的情況下做到這一點的最佳方式是什麼?Rails 4遷移將列數據類型從字符串更改爲整數並保留後備數據(postgres)

這是當前遷移:

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 } 
... 

如何更新舊的數據?

回答

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

可以在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

相關問題