在Rails和Postgresql迁移中, 默认值未能自动填充

7

我现在正在尝试运行这个迁移:

class AddDroppedProjectsCountToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :dropped_projects, :integer, {:default=>0, :required=>true}
  end

  def self.down
    remove_column :users, :dropped_projects
  end
end

列已正确添加,但旧记录中没有一个被填充为0,它们是nil。我尝试使用 default=> '0' ,但没有用。有任何想法可能是什么原因?(Rails 3.0.3)


编辑添加:当我创建一个新用户时,它可以正常工作,一切看起来都是正确的。只有旧用户在表中的该值仍为nil。

3个回答

13

如果你这样说会发生什么:

def self.up
  add_column :users, :dropped_projects, :integer, :null => false, :default => 0
end

如果没有 :null=>false,你仍然允许 NULL 存在于 dropped_projects 中,所以 PostgreSQL 没有理由将它们设为 0。此外,我不认为 :requiredadd_column 的有效选项;因为选项只是一个简单的 Hash,而且 add_column 只寻找已知的选项,所以你迷路的 :required 选项会被静默忽略。


非常成功!谢谢Mu。填充一些0居然需要这么多步骤,真是太奇怪了。 - Dave G
@Dave G:还要看看我的有关 :required 的小更新。NULL的问题在于有时它意味着“未知”,而有时它意味着“不存在”。数据库无法区分这两种情况;如果你没有明确表示“不允许NULL”,那么DB就无法知道这些NULL是默认值还是显式的NULL。 - mu is too short
它对我起作用了。如果您不想强制使用无空值,还有其他方法吗?如果您不想强制使用默认值,而只是更改已经存在于数据库中并受迁移影响的行的值,该怎么办? - B Seven
@B Seven:只需将 :null=>false 留空即可,但这可能对现有行没有任何影响,您可以始终使用原始 SQL 执行“UPDATE table ...”并执行一半更新;当 SQL 是完成工作的最直接和有效的方式时,没有理由避免使用它。 - mu is too short

3
你可以这样做:
(摘自http://apidock.com/rails/ActiveRecord/Migration
使用更改表后的模型 有时您想添加一个列并在迁移中立即填充它。在这种情况下,您需要调用Base#reset_column_information以确保模型具有新列添加后的最新列数据。示例:
class AddPeopleSalary < ActiveRecord::Migration
  def up
    add_column :people, :salary, :integer
    Person.reset_column_information
    Person.all.each do |p|
      p.update_column :salary, SalaryCalculator.compute(p)
    end
  end
end

如果您在生产环境中有一个庞大的现有人员集合,会发生什么? - Bogdan Popa

1
我相信这是因为你正在更改旧的迁移,而不是创建一个新的。在这种情况下,解决方案是检查模式文件(schema.rb)。它不会自动更改,并添加。

t.integer "dropped_projects", default: 0, null: false

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接