Rails 3.1:无法在添加列的同一迁移中写入列

发布于 2024-12-27 23:37:26 字数 704 浏览 0 评论 0 原文

我有一个可以正常运行的 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 来强制用户类在循环之前重新加载。没有骰子。

当我将其分成两次迁移时,就达到了预期的效果。有人对此有解释吗?我发誓我什至在过去的迁移的同一个项目中完成了此操作。

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

I had an add_column migration that would run fine. However, after running it and firing up a console, I would find the first_name and last_name columns completely empty. I tried using save! instead and it had the same effect--no errors reported. Here's the original:

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

I also thought this might be some class loading issue, so I inserted the line User to force the user class to reload before the loop. No dice.

When I split this up into two migrations, the desired effect was achieved. Does someone have an explanation for this? I swear I've even done this in the same project with past migrations.

Other notes: Devise for user engine, added the new columns to attr_accessible in User class before running migration.

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

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

发布评论

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

评论(1

夏雨凉 2025-01-03 23:37:26

在迁移运行之前,您正在某处加载 Users 类,因此 User 对它自己的结构有点困惑。解决方案是在之后调用 reset_column_information添加您的专栏:

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

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

迁移指南的 -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)导致加载用户及其架构,然后您添加一列。但是,显然,当 u.first_name 调用起作用时,User 仅部分了解新列,但在 User 内部缓存了某些内容以防止将属性写入数据库。

You're loading the Users class somewhere before your migration runs so User is a little confused about its own structure. The solution is to call reset_column_information after adding your column:

Resets all the cached information about columns, which will cause them to be reloaded on the next request.

The most common usage pattern for this method is probably in a migration, when just after creating a table you want to populate it with some default values

The Using Models in Your Migrations section of the Migrations Guide might be worth a look as well.

Try rolling back and using a migration like this:

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

I checked this with three migrations like this:

# 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

The first one works just fine, the second one adds some_column but leaves it with NULL values, the third one also works.

I'd guess that something in your application initialization (possibly from Devise) is causing User and its schema to be loaded, then you add a column. But, apparently, User only partly knows about the new column as the u.first_name call works but something is cached inside User to prevents the attribute from being written to the database.

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