【问题标题】:Add a column in a Rails Active Record migration with an initial value based on other columns在 Rails Active Record 迁移中添加一个列,其初始值基于其他列
【发布时间】:2017-09-20 18:37:34
【问题描述】:

我正在尝试使用 Rails 中的 Active Record 迁移向现有表添加列。我需要该列的初始值基于表中的其他列。有没有办法在 Active Record 迁移中做到这一点?

为了更具体,假设我有以下内容:

my_table
----------------
first_name: text
last_name: text

我想添加一个初始值为concat(first_name, ' ', last_name'full_name 文本列。请注意,我不想在列上设置默认值,因为我打算让应用程序继续填充它(初始默认值只是为现有记录提供一个合理的起始值)。

如何在迁移中做到这一点?理想情况下,我想使用 add_column 或类似的,但如果这不能工作,一个可行的替代方案是可以接受的。

请注意,已经存在一个几乎相同的问题 (add a database column with Rails migration and populate it based on another column),但似乎没有一个答案可以完全回答这个问题。

【问题讨论】:

  • @DanilSperansky 确实如此,尽管当模型在迁移中超过该点时它可能会受到问题的影响(在另一个答案中指出),这就是为什么我发布了一个 SQL 解决方案更新。由于它不会尝试实例化活动记录对象,因此我能想到的唯一极端情况是,如果之后有迁移重命名或删除表。

标签: sql ruby-on-rails activerecord rails-activerecord rails-migrations


【解决方案1】:

您可以在add_column 之后使用update_all。对于 MySQL:

Person.update_all('full_name = concat(first_name, " ", last_name)')

【讨论】:

  • 根据我对问题本身的评论,我想如果后续迁移删除或重命名此表,这将失败,因为具有该名称的活动记录对象将不再存在以调用 update_all on .换句话说,它不是完全面向未来的。
【解决方案2】:

我最终使用add_column 添加列,然后使用直接 SQL 更新列的值。我使用了直接 SQL 而不是 this answer 中的模型,因为那时它不依赖于模型的当前状态与基于正在运行的迁移的表的当前状态。

class AddFullName < ActiveRecord::Migration
  def up
    add_column :my_table, :full_name, :text
    execute "update my_table set full_name = concat(first_name, ' ', last_name)"
  end

  def down
    remove_column :my_table, :full_name
  end
end

也就是说,如果有更好或更惯用的方法,我会全力以赴。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多