【问题标题】:Rails 3.1: can't write to column in same migration that adds itRails 3.1:无法写入添加它的同一迁移中的列
【发布时间】:2012-01-20 00:31:20
【问题描述】:

我有一个运行良好的 add_column 迁移。但是,在运行它并启动控制台后,我会发现 first_name 和 last_name 列完全为空。我尝试改用save!,效果相同——没有报告错误。原文如下:

class UserAddFirstNameAndLastName < ActiveRecord::Migration
  def change
    # add column first name, last name string
    add_column :users, :first_name, :string
    add_column :users, :last_name, :string

    User.all.each do |u|
      u.first_name = 'first name'
      u.last_name = 'last name'
      u.save
    end
  end
end

我还认为这可能是一些类加载问题,所以我插入了User 行以强制用户类在循环之前重新加载。没有骰子。

当我把它分成两个迁移时,达到了预期的效果。有人对此有解释吗?我发誓我什至在过去迁移的同一个项目中做过这个。

其他说明:为用户引擎设计,在运行迁移之前将新列添加到用户类中的attr_accessible

【问题讨论】:

  • mu is too short 有一个很好的答案来解释正在发生的事情和做什么,但我也建议将这两个分成不同的迁移。在一个中创建列,在另一个中填充。这可以防止您看到的问题并使回滚更不容易出错。

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


【解决方案1】:

您在迁移运行之前在某处加载了 Users 类,因此 User 对其自身的结构有点困惑。解决方案是在添加您的列后致电reset_column_information

重置有关列的所有缓存信息,这将导致它们在下一次请求时重新加载。

此方法最常见的使用模式可能是在迁移中,即在创建表后您想用一些默认值填充它

Migrations GuideUsing Models in Your Migrations 部分可能也值得一看。

尝试回滚并使用如下迁移:

def change
  # add column first name, last name string
  add_column :users, :first_name, :string
  add_column :users, :last_name, :string

  User.reset_column_information

  User.all.each do |u|
    u.first_name = 'first name'
    u.last_name = 'last name'
    u.save
  end
end

我用这样的三个迁移检查了这一点:

# 1: Don't touch Model before the new columns.
def change
  add_column :models, :some_column, :string
  Model.all.each { |m| m.some_column = 'pancakes'; m.save }
end

# 2: Pull in Model before adding the new columns.
def change
  puts Model.all.count
  add_column :models, :some_column, :string
  Model.all.each { |m| m.some_column = 'pancakes'; m.save }
end

# 3: Pull in Model before adding the new columns but use reset_column_information
def change
  puts Model.all.count
  add_column :models, :some_column, :string
  Model.reset_column_information
  Model.all.each { |m| m.some_column = 'pancakes'; m.save }
end

第一个可以正常工作,第二个添加 some_column 但将其保留为 NULL 值,第三个也可以。

我猜你的应用程序初始化中的某些东西(可能来自 Devise)导致 User 及其架构被加载,然后你添加一个列。但是,显然,由于 u.first_name 调用有效,User 仅部分了解新列,但 User 内部缓存了一些内容以防止将属性写入数据库。

【讨论】:

  • 确认这是一个警告的问题。我刚刚在一次迁移中一起使用了您的第一个和第三个示例。第一个没有保存到数据库中。我 grep 了我们的 DB 文件夹,我之前是对的——我有像这样保存的旧迁移。我们添加到我们项目中的东西导致模型在迁移之前预加载......我怀疑它可能是active_reload gem。我们还没有升级到 Rails 3.2,但我注意到这是一个标准功能。如果我有时间,我希望通过测试来确认/反驳这一点。
  • @Eric:初始化中的某些内容正在预加载您的模型类。 (1) 为我工作,因为我的初始化中没有预加载任何东西; (2) 和 (3) 中的 puts Model.all.count 只是模拟环境中正在进行的预加载的简单方法。 active_reload 听起来确实是个嫌疑犯。如果您在一次迁移中更改和使用模型,添加 reset_column_information 可能是一个好习惯。
  • @KeesBriggs 我刚刚用 Rails 4.2.4 检查了reset_column_information 方法,工作正常。你会发生什么?
猜你喜欢
  • 2011-10-09
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 2011-06-24
  • 1970-01-01
  • 2023-03-14
  • 2017-02-17
  • 2014-05-13
相关资源
最近更新 更多