Rails Migrations 可以用来转换数据吗?

发布于 2024-07-19 19:17:51 字数 434 浏览 5 评论 0原文

我正在尝试将 Rails 应用程序中的列转换为参数,假设我正在尝试将 users 表中的 age 列更改为字符串表示形式比一个整数。

在我的迁移中我有这个;

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

但它似乎不起作用,我在这里尝试的迁移是否可行?

I'm trying to convert a column in my Rails app, for arguments sake let's pretend I'm trying to change the age column in my users table to a string representation rather than an int.

In my migration I have this;

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

But it doesn't seem to be working, is what I'm attempting here even possible with migrations?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

溇涏 2024-07-26 19:17:51

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

不过,您需要重新加载在迁移中更新的模型类的列信息,以便 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

在单独的说明中,请注意,如果您的表很大,则逐一进行更新将花费很长的时间。请小心。

What you're trying to do is possible, and I would say the correct thing to do.

You need, though, to reload the column info for the model classes you're updating in the migration, so that Rails knows about the new columns. Try this:

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

On a separate note, please note that if your table is large, doing updates one by one will take a looong time.. Be careful with that.

相对绾红妆 2024-07-26 19:17:51

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

一般来说,在迁移中操作数据是一个坏主意。 如果模型逻辑发生变化,直接模型访问的迁移可能会陷入困境。

想象一下,在第二次迁移中,您添加了一个新列。 您想用新数据播种该列。

我们还假设几周后您向模型添加了一个新的验证 - 该验证对第二次迁移中尚不存在的字段进行操作。 如果您要从迁移 0 构建数据库,则会遇到一些问题。

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

Since I'm new here I can't comment on the above so I'll add my own answer.

GENERALLY manipulating data in migrations is a BAD idea. Migrations with direct model access can get stuck if the model logic changes.

Imagine in your second migration you've added a new column. You want to seed that column with new data.

Let's also say a few weeks later you add a new validation to the model - a validation that operates on a field that does not yet exist in your second migration. if you ever were to construct the database from migration 0, you'd have some problems.

I strongly suggest using migrations to alter columns and other means to manage database data, especially when moving to production.

筱果果 2024-07-26 19:17:51

这是我运行的用于转换数据的示例迁移。 您可以轻松地将其转换为使用整数而不是字符串。 在 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

Here is an example migration I ran to convert data. You can easily convert it to use integers instead of strings. Making the conversion in SQL is much faster than loading each row in 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

And to test it:

rake db:migrate
rake db:rollback
rake db:migrate
简单 2024-07-26 19:17:51

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

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

002_setup_meta_data.rb
002_meta_data.yaml


007_change_meta_data.rb
007_meta_data.yaml

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

I would say that if you can "undo" the imported data when rolling back the migration version, then it's appropriate to put imports into the migration.

For example, I have a migration which sets up a lot of lookup tables and other meta-data. The data for these tables are populated during this phase. As the data for these lookup tables changes, I create new YAML files storing the meta-data and load those files in subsequent migrations (and un-do those YAMLS, re-loading the previous YAML file when backing out of a migration version). This is pretty clean. I have files (in different well-defined folders in my case) with these files:

002_setup_meta_data.rb
002_meta_data.yaml


007_change_meta_data.rb
007_meta_data.yaml

If you're importing "production" data from another system into transactional (non-static) tables, then I would say using migrations is not appropriate. Then I would follow Brian Hogan's advice of using rake tasks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文