使用 Rails 迁移添加一个数据库列并基于另一列填充它 [英] add a database column with Rails migration and populate it based on another column

查看:14
本文介绍了使用 Rails 迁移添加一个数据库列并基于另一列填充它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写迁移以向表中添加列.该列的值取决于另外两个现有列的值.最好/最快的方法是什么?目前我有这个但不确定这是否是最好的方法,因为组表可能非常大.

类 AddColorToGroup <ActiveRecord::迁移def self.upadd_column :组,:颜色,:字符串组 = Group.all.each 做 |g|c = "red" 如果 g.is_active &&is_livec = "绿色" 如果 g.is_activec = "橙色"g.update_attribute(:type, c)结尾结尾def self.down结尾结尾

解决方案

像这样从迁移中引用模型通常是个坏主意.问题是迁移按顺序运行并随时更改数据库状态,但您的模型根本没有版本控制.无法保证编写迁移时存在的模型将来仍与迁移代码兼容.

例如,如果您将来更改 is_activeis_live 属性的行为,则此迁移可能会中断.这种较旧的迁移将首先针对新模型代码运行,并且可能会失败.在您的基本示例中,它可能不会突然出现,但是在添加字段并且无法运行验证之前,这已经让我在部署中烧毁了(我知道您的代码正在跳过验证,但总的来说这是一个问题).

我最喜欢的解决方案是使用纯 SQL 进行所有此类迁移.看起来你已经考虑过了,所以我假设你已经知道在那里做什么.

另一种选择,如果您有一些复杂的业务逻辑或只是希望代码看起来更像 Railsy,则在迁移中包含模型的基本版本在编写迁移时存在文件本身.例如,您可以将此类放在迁移文件中:

类组 

活动记录::基础结尾

就您而言,仅此一项就足以保证模型不会损坏.假设此时 activelive 是表中的布尔字段(因此将来无论何时运行此迁移),您将不再需要任何代码一点也不.如果您有更复杂的业务逻辑,您可以将其包含在这个特定于迁移的模型版本中.

您甚至可以考虑将模型中的整个方法复制到迁移版本中.如果您这样做,请记住,您不应该从那里引用应用程序中的任何外部模型或库,如果它们将来有可能发生变化.这包括 gems,甚至可能包括一些核心 Ruby/Rails 类,因为 gems 中的 API 破坏性更改非常常见(我在看你,Rails 3.0、3.1 和 3.2!).

I'm writing a migration to add a column to a table. The value of the column is dependent on the value of two more existing columns. What is the best/fastest way to do this? Currently I have this but not sure if it's the best way since the groups table is can be very large.

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

解决方案

It's generally a bad idea to reference your models from your migrations like this. The problem is that the migrations run in order and change the database state as they go, but your models are not versioned at all. There's no guarantee that the model as it existed when the migration was written will still be compatible with the migration code in the future.

For example, if you change the behavior of the is_active or is_live attributes in the future, then this migration might break. This older migration is going to run first, against the new model code, and may fail. In your basic example here, it might not crop up, but this has burned me in deployment before when fields were added and validations couldn't run (I know your code is skipping validations, but in general this is a concern).

My favorite solution to this is to do all migrations of this sort using plain SQL. It looks like you've already considered that, so I'm going to assume you already know what to do there.

Another option, if you have some hairy business logic or just want the code to look more Railsy, is to include a basic version of the model as it exists when the migration is written in the migration file itself. For example, you could put this class in the migration file:

class Group < ActiveRecord::Base
end

In your case, that alone is probably sufficient to guarantee that the model will not break. Assuming active and live are boolean fields in the table at this time (and thus would be whenever this migration was run in the future), you won't need any more code at all. If you had more complex business logic, you could include it in this migration-specific version of model.

You might even consider copying whole methods from your model into the migration version. If you do that, bear in mind that you shouldn't reference any external models or libraries in your app from there, either, if there's any chance that they will change in the future. This includes gems and even possibly some core Ruby/Rails classes, because API-breaking changes in gems are very common (I'm looking at you, Rails 3.0, 3.1, and 3.2!).

这篇关于使用 Rails 迁移添加一个数据库列并基于另一列填充它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆