7

我正在寫一個移動到列添加到表。該列的值取決於另外兩個現有列的值。什麼是最好的/最快的方式來做到這一點? 目前我有這個,但不知道這是否是最好的方式,因爲groups表可能非常大。添加一個數據庫列與Rails的遷移,並填充它基於另一列

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Groups = Group.all.each do |g| 
     c = "red" if g.is_active && is_live 
     c = "green" if g.is_active 
     c = "orange" 
     g.update_attribute(:type, c) 
    end 
    end 

    def self.down 

    end 
end 
+0

爲什麼倒下來的東西不起作用? – Robert 2013-03-08 01:17:01

+0

這只是我在編輯時犯的一個錯字;) – user1404536 2013-03-08 01:21:01

回答

1

我會在你的ActiveRecord模型做到這一點的

after_create 
# or 
after_save 

或遷移你可能必須做一些這樣的SQL:

execute('update groups set color = <another column>') 

這裏是一個例子Rails的指南:

http://guides.rubyonrails.org/migrations.html#using-the-up-down-methods

+2

謝謝,但是應該爲所有現有組預填充該列。這隻適用於新創建的組。 – user1404536 2013-03-08 00:41:01

2

我會強烈建議做了三個總查詢代替。始終利用數據庫與數組中的一堆項目進行循環。我會認爲這樣的事情可以工作。

爲了編寫這個目的,我假設is_active檢查活動的字段,其中1是活動的。我會假設生活是一樣的。

Rails 3的方法

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Group.where(active: 1, live: 1).update_all(type: "red") 
    Group.where(active: 1, live: 0).update_all(type: "green") 
    Group.where(active: 0, live: 0).update_all(type: "orange") 
    end 
end 

隨時都可以查閱update_all here的文檔。

的Rails 2.x的方法

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Group.update_all("type = red", "active = 1 AND live = 1") 
    Group.update_all("type = red", "active = 1 AND live = 0") 
    Group.update_all("type = red", "active = 0 AND live = 0") 
    end 
end 

Rails 2 documentation

+0

:(我的應用程序沒有使用Rails 3,謝謝您的好意! – user1404536 2013-03-08 01:20:09

+0

回答更新,包括響應的Rails 2.x版。 – Robert 2013-03-08 01:24:15

+0

這是否解決了問題? – Robert 2013-03-08 02:01:56

12

這通常是一個壞主意,從你的遷移這樣的引用您的機型。問題在於遷移按順序運行,並隨着數據庫狀態的變化而變化,但是您的模型根本沒有版本。不能保證在編寫遷移時存在的模型仍然與將來的遷移代碼兼容。

例如,如果您將來改變is_activeis_live屬性的行爲,那麼此遷移可能會中斷。這種較舊的遷移將首先針對新的模型代碼運行,並可能失敗。在這裏的基本示例中,它可能不會出現,但是在添加字段和驗證無法運行之前(我知道您的代碼正在跳過驗證,但通常這是一個問題)之前,這已經燒燬了我的部署。

我最喜歡的解決方案是使用普通SQL進行這種類型的所有遷移。看起來你已經考慮過了,所以我會假設你已經知道該怎麼做了。

另一種選擇,如果你有一些毛茸茸的業務邏輯,或者只是想代碼看起來更Railsy,是包括模型的基本版本,因爲它在遷移中遷移文件本身寫入存在。例如,你可以把這個類在遷移文件:

class Group < ActiveRecord::Base 
end 

在你的情況,單獨大概是足以保證該模型不會打破。假設activelive此時是表中的布爾字段(並且因此將來會在將來運行此遷移時),則根本不需要任何更多的代碼。如果您擁有更復雜的業務邏輯,則可以將其包含在此特定於遷移的模型版本中。

您甚至可以考慮將模型中的整個方法複製到遷移版本中。如果你這樣做,請記住,如果你有將來有可能改變的地方,那麼你不應該在你的應用中引用任何外部模型或庫。這包括寶石,甚至可能是一些核心的Ruby/Rails類,因爲寶石中破壞API的變化非常常見(我在看你,Rails 3.0,3.1和3.2!)。

0

在類似的情況下,我結束了使用add_column,然後使用直接SQL更新列的值加上列。我使用了直接SQL,而不是根據Jim Stewart's answer的模型,因爲它不依賴於模型的當前狀態與基於正在運行的遷移的表的當前狀態。

class AddColorToGroup < ActiveRecord::Migration 
    def up 
    add_column :groups, :color, :string 
    execute "update groups set color = case when is_active and is_live then 'red' when is_active then 'green' else 'orange' end" 
    end 

    def down 
    remove_column :groups, :color 
    end 
end 
相關問題