Real-world migrations in Rails apps can sometimes involve both schema changes and data changes. For instance, if you are moving a column from one table to another, you'll need to add a new column, move some data, and then delete the old column.
# Assume the following are defined:
# GenericAuthor for table 'authors'
# GenericBook for table 'books'
def up
add_column :books, :genre, :string
GenericAuthor.find_each do |author|
book = GenericBook.find_by(author_id: author.id)
book.update!(genre: author.genre)
end
remove_column :authors, :genre
end
This migration looks straightforward, but you may find that no data actually
gets transferred to the genre
column on books
. This is because as a
performance optimization, Rails has cached the scema. Thus an ActiveRecord
modification like book.update!
will be working off a version of the schema
that doesn't include genre
as a column.
We can ensure ActiveRecord
is using the latest column informtion for the
books
table by calling
reset_column_information
.
def up
add_column :books, :genre, :string
GenericBook.reset_column_information
GenericAuthor.find_each do |author|
book = GenericBook.find_by(author_id: author.id)
book.update!(genre: author.genre)
end
remove_column :authors, :genre
end
Now the update will work and genre
will be set on books
.