From 6351bb7c91173df97ddb858a8de1f6457b659850 Mon Sep 17 00:00:00 2001 From: jbranchaud Date: Sun, 19 May 2019 14:53:19 -0500 Subject: [PATCH] Add Ensure Migrations Use The Latest Schema as a rails til --- README.md | 3 +- ...ensure-migrations-use-the-latest-schema.md | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 rails/ensure-migrations-use-the-latest-schema.md diff --git a/README.md b/README.md index ed8c4ae..e42fab1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ smart people at [Hashrocket](http://hashrocket.com/). For a steady stream of TILs from a variety of rocketeers, checkout [til.hashrocket.com](https://til.hashrocket.com/). -_812 TILs and counting..._ +_813 TILs and counting..._ --- @@ -493,6 +493,7 @@ _812 TILs and counting..._ - [Delete Paranoid Records](rails/delete-paranoid-records.md) - [Demodulize A Class Name](rails/demodulize-a-class-name.md) - [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md) +- [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md) - [Generating And Executing SQL](rails/generating-and-executing-sql.md) - [Hash Slicing](rails/hash-slicing.md) - [Ignore Poltergeist JavaScript Errors](rails/ignore-poltergeist-javascript-errors.md) diff --git a/rails/ensure-migrations-use-the-latest-schema.md b/rails/ensure-migrations-use-the-latest-schema.md new file mode 100644 index 0000000..d70db8d --- /dev/null +++ b/rails/ensure-migrations-use-the-latest-schema.md @@ -0,0 +1,50 @@ +# Ensure Migrations Use The Latest Schema + +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. + +```ruby +// 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`](https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema/ClassMethods.html#method-i-reset_column_information). + +```ruby +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`.