问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/8935350/rails-3-1-cant-write-to-column-in-same-migration-that-adds-it