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

Eri*_* Hu 23 activerecord ruby-on-rails rails-migrations ruby-on-rails-3 rails-activerecord

我有一个可以正常运行的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
Run Code Online (Sandbox Code Playgroud)

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

当我将其拆分为两次迁移时,实现了期望的效果.有人对此有解释吗?我发誓我甚至在过去迁移的同一个项目中做过这个.

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

mu *_*ort 37

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

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

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

" 迁移指南"中的" 迁移中使用模型"部分也值得一看.

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

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
Run Code Online (Sandbox Code Playgroud)

我通过三次迁移检查了这个:

# 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
Run Code Online (Sandbox Code Playgroud)

第一个工作正常,第二个添加,some_column但留下NULL值,第三个也有效.

我猜你的应用程序初始化(可能来自Devise)导致用户及其架构被加载,然后你添加一列.但是,显然,User只是部分知道新列,因为u.first_name调用有效,但有些内容缓存在User内部,以防止将属性写入数据库.