我正在写一个迁移到列添加到表。 列的值是依赖于两个现有的列的值。 什么是做到这一点的最好/最快的方法是什么? 目前我有这个,但不知道这是否是最好的方法,自组表可能非常大。
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
它通常是一个坏主意,你的迁移这样的引用您的机型。 问题是,迁移,以便运行并更改数据库的状态,因为他们去,但你的模型是不是在所有版本。 有没有保证,当被写入迁移仍然会在未来迁移代码兼容的模式,因为它的存在。
例如,如果你改变的行为is_active
或is_live
在未来的属性,那么这种迁移可能会中断。 这种旧的迁移将会首先运行,对新模式的代码,并可能会失败。 在这里您简单的例子,它可能不会突然出现,但是这已经烧到我在部署时添加字段和验证无法运行(我知道你的代码被跳过验证,但总的来说,这是一个问题)了。
我最喜欢的解决办法是做这样使用普通的SQL的所有迁移。 看起来你已经考虑到,所以我会假设你已经知道该怎么做在那里。
另一种选择,如果你有一些毛茸茸的业务逻辑,或者只是想代码看起来更Railsy,是包括模型的基本版本,因为它在迁移写入迁移文件本身存在 。 例如,你可以把这个类在迁移文件:
class Group < ActiveRecord::Base
end
在你的情况下,单独大概是足以保证该模型不会打破。 假设active
和live
在表中布尔字段在这个时候(因此是每当这个迁移在将来运行),你不需要任何更多的代码在所有。 如果你有更复杂的业务逻辑,你可以将它包括在模型的这个特定迁移版本。
你甚至可以考虑从复制模型整个方法到迁移版本。 如果你这样做,要记住,你不应该引用任何外部模型或库在你的应用程序从那里,或者说,如果有任何机会,他们将在未来发生改变。 这包括宝石,甚至可能还有一些核心的Ruby / Rails类,因为在宝石API的最新变化是很常见的(我看着你,Rails的3.0,3.1和3.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的文档在这里 。
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
轨道2文档
我会在这样做
after_create
# or
after_save
在你的ActiveRecord模型:
class Group < ActiveRecord::Base
attr_accessor :color
after_create :add_color
private
def add_color
self.color = #the color (wherever you get it from)
end
end
或者迁移你可能必须做一些这样的SQL:
execute('update groups set color = <another column>')
这里是Rails的导游一个例子:
http://guides.rubyonrails.org/migrations.html#using-the-up-down-methods
在类似的情况下,我结束了使用添加列add_column
,然后使用直接SQL更新列的值。 我直接用SQL,而不是每个模型吉姆·斯图尔特的回答 ,自此基础上迁移正在运行不依赖于模型对比表的当前状态的当前状态。
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
文章来源: add a database column with Rails migration and populate it based on another column