可以使用Rails迁移来转换数据吗?

时间:2009-05-11 20:19:06

标签: ruby-on-rails ruby migration

我正在尝试在我的Rails应用程序中转换一个列,但为了论证,让我假装我试图将age表中的users列更改为字符串表示而不是int

在我的迁移中,我有这个;

def.self up
    add_column :users, :age_text, :string

    users = User.find(:all)

    users.each do |u|
       u.age_text = convert_to_text(u.age)
       u.save
    end
end

def self.convert_to_text(number)
   #code here to convert 1 to 'one' etc
end

但它似乎没有起作用,我在这里尝试迁移甚至可能吗?

4 个答案:

答案 0 :(得分:58)

你想做的事情是可能的,我会说正确的事情。

但是,您需要重新加载要在迁移中更新的模型类的列信息,以便Rails了解新列。试试这个:

def.self up
    add_column :users, :age_text, :string

    User.reset_column_information 

    users = User.find(:all)

    users.each do |u|
       u.age_text = convert_to_text(u.age)
       u.save
    end
end

另请注意,如果您的桌子很大,逐个更新会花费很长时间。请注意这一点。

答案 1 :(得分:39)

由于我是新来的,所以我不能对上述内容发表评论,所以我会添加自己的答案。

通常在迁移中操纵数据是一个不错的想法。如果模型逻辑发生变化,直接模型访问的迁移可能会卡住。

想象一下,在第二次迁移中,您添加了一个新列。您希望使用新数据为该列提供种子。

我们还要说几周后你会为模型添加一个新的验证 - 一个在第二次迁移中尚不存在的字段上运行的验证。如果您曾经从迁移0构建数据库,那么您会遇到一些问题。

我强烈建议使用迁移来更改列和其他方法来管理数据库数据,尤其是在迁移到生产时。

答案 2 :(得分:4)

以下是我运行转换数据的示例迁移。您可以轻松地将其转换为使用整数而不是字符串。在SQL中进行转换比在Rails中加载每一行要快得多。

class ConvertCommentTextToText < ActiveRecord::Migration
  def up
    add_column :comments, :text_tmp, :text
    # copy text column
    execute <<-SQL
      update comments set text_tmp = text
    SQL
    remove_column :comments, :text
    rename_column :comments, :text_tmp, :text
  end

  def down
    add_column :comments, :text_tmp, :string
    # copy text column
    execute <<-SQL
      update comments set text_tmp = text
    SQL
    remove_column :comments, :text
    rename_column :comments, :text_tmp, :text
  end

end

并测试它:

rake db:migrate
rake db:rollback
rake db:migrate

答案 3 :(得分:0)

我想说,如果您在回滚迁移版本时可以“撤消”导入的数据,那么将导入放入迁移是合适的。

例如,我有一个迁移,它设置了很多查找表和其他元数据。在此阶段填充这些表的数据。随着这些查找表的数据发生变化,我创建了新的YAML文件,用于存储元数据并在后续迁移中加载这些文件(并取消那些YAMLS,在退出迁移版本时重新加载以前的YAML文件)。这很干净。我有这些文件的文件(在我的情况下在不同的明确定义的文件夹中):

002_setup_meta_data.rb
002_meta_data.yaml


007_change_meta_data.rb
007_meta_data.yaml

如果您将“生产”数据从另一个系统导入到事务(非静态)表中,那么我会说使用迁移是不合适的。然后我会遵循Brian Hogan关于使用rake任务的建议。