通过迁移为列添加默认值

Posted

技术标签:

【中文标题】通过迁移为列添加默认值【英文标题】:Add a default value to a column through a migration 【发布时间】:2011-10-29 05:47:58 【问题描述】:

如何向通过迁移已存在的列添加默认值?

我能找到的所有文档都向您展示了如果该列尚不存在但在这种情况下存在的情况下如何执行此操作。

【问题讨论】:

【参考方案1】:

这是你可以做的:

class Profile < ActiveRecord::Base
  before_save :set_default_val

  def set_default_val
    self.send_updates = 'val' unless self.send_updates
  end
end

编辑:...但显然这是一个新手错误!

【讨论】:

最好在架构中设置默认值而不是before_save 多么糟糕的建议 同意,真的很糟糕 哎呀,你在模型级别而不是数据库级别做某事得到了很多热量。 -38 是一个传奇的分数。 什么菜鸟的错误... ;-)【参考方案2】:

对于 Rails 4+,请使用 change_column_default

def change
  change_column_default :table, :column, value
end

【讨论】:

这非常棒,特别是如果您有一个正在添加列并为现有记录设置默认值的迁移。例如:def change `add_column :foos, :name, default: "something for existing values"` `change_column_default :foos, :name, default: ""` end 这个迁移有一个奇怪的行为。在您的示例中,这是不可逆转的。 edgeguides.rubyonrails.org/active_record_migrations.html 建议这样使用它:change_column_default :products, :approved, from: true, to: false — 但它也不起作用。 不能使用那个回滚? 通常是这样,对于几乎所有“更改”子句,因为所有先前的状态通常都是显式的,例如列的存在、它的类型等。更改可以回滚,如图所示当且仅当先前存在有效的显式默认值时。由于默认值未定义很常见,因此您可能会遇到问题。【参考方案3】:
change_column_default :employees, :foreign, false

【讨论】:

@DenisLins 我同意你的看法,所以我做了一些研究以找出它可能不支持的原因,结果表明特定的数据库适配器可能不支持它,因为它已实现在那个级别。在抽象模型中实现之前,接受的答案仍然是最安全的选择。 apidock.com/rails/ActiveRecord/ConnectionAdapters/… 除此之外,如果您希望它是可逆的,您需要指定 from:to: :) 使用 fromto 被添加到 Rails 5+ 的这个提交中:github.com/rails/rails/pull/20018/files【参考方案4】:

**Rails 4.X +**

从 Rails 4 开始,您无法生成迁移以将列添加到具有默认值的表中, 以下步骤将新列添加到现有表中,默认值为 true 或 false。

1。从命令行运行迁移以添加新列

$ rails generate migration add_columnname_to_tablename columnname:boolean

上述命令将在您的表格中添加一个新列。

2。通过编辑创建的新迁移文件将新列值设置为 TRUE/FALSE。

class AddColumnnameToTablename < ActiveRecord::Migration
  def change
    add_column :table_name, :column_name, :boolean, default: false
  end
end

**3。要对您的应用程序数据库表进行更改,请在终端中运行以下命令**

$ rake db:migrate

【讨论】:

这与 rails 3+ 或 2+ 有何不同? 有谁知道这是否已被合并到 Rails 5 中? @sambecker 我知道回复您的评论可能有点晚了,但它在 Rails 6.0.3.1 上对我有用 @Mathyou 很高兴知道。在 Rails 6 中,新表可以包含具有默认值的列吗?还是还是单独迁移? @sambecker 您绝对可以在新表迁移中设置默认值。我在此类迁移中的一个专栏如下所示:t.boolean :is_active, :null =&gt; false, :default =&gt; false【参考方案5】:

使用def change 意味着您应该编写可逆的迁移。而change_column 是不可逆的。你可以上,但你不能下,因为change_column是不可逆的。

相反,虽然它可能会多出几行,但您应该使用 def updef down

所以如果你有一列没有默认值,那么你应该这样做来添加一个默认值。

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: nil
end

或者,如果您想更改现有列的默认值。

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: true
end

【讨论】:

【参考方案6】:

你应该这样做:

change_column :users, :admin, :boolean, :default => false

但某些数据库,如 PostgreSQL,不会更新之前创建的行的字段,因此请确保在迁移时也手动更新字段。

【讨论】:

如果您需要可逆迁移,请将其放在 up 块中,而不是 change 块中。您可以将 down 块留空。它不会将表恢复到原始状态,但可以回滚迁移。 这会保持数据完整吗? 在PostgreSQL上,是的,我不知道在其他数据库上会发生什么。 您说“确保在迁移时手动更新字段”是什么意思?如何做到这一点? 我在 PostgreSQL 上试了一下,它更新了之前创建的字段。【参考方案7】:

执行:

rails generate migration add_column_to_table column:boolean

它将生成此迁移:

class AddColumnToTable < ActiveRecord::Migration
  def change
    add_column :table, :column, :boolean
  end
end

设置默认值加 :default => 1

add_column :table, :column, :boolean, :default => 1

运行:

rake db:迁移

【讨论】:

现在默认值 1 不完全是布尔值;)此外,此示例 添加 一个新列,而不是更改现有列,这是 OP 想要的实现 @radiospiel 实际上,1 也是一个布尔值 :) 您还需要在外键表中创建一条 ID 为 1 的记录才能正常工作,以避免出现 Key is not present in table error

以上是关于通过迁移为列添加默认值的主要内容,如果未能解决你的问题,请参考以下文章

将默认值设置为列代码优先方法[重复]

创建迁移文件时分配默认值

Laravel 迁移:添加具有现有列默认值的列

SQL 将索引(订单值)设置为列

在实体优先迁移中为新Guid列添加默认值

代码优先迁移:如何为新属性设置默认值?