Noh | エンジニア向け情報共有コミュニティ
Signup / Login

Safely delete columns in a Ruby on Rails app in production

ruby
rails
postgresql

投稿日: 2024/06/25

更新日: 2024/07/01

This article is a translation of the following article.

https://noh.ink/articles/Fm3rabTJh6vVnpBUyhpr

Procedure

  1. Fix all the code using the column to be deleted
  2. Add ignored_columns to the column
  3. Release the changes made so far
  4. Delete the column (Create a migration file to delete the column and update schema.rb)
  5. Remove ignored_columns
  6. Release the changes

Modify all codes that use the column to be deleted

Before actually deleting the column, all instances of the column to be deleted will be modified in order to ensure that it is not being used.

Add ignored_columns to the columns

ActiveRecord caches column information in the schema cache.

When deleting a column suddenly for a service in operation such as a production environment, the Rails application behaves as if the deleted column still exists because the schema before deletion is cached.

Rails will behave as ignoring the specified columns when you add columns to ignored_columns as follows.

app/models/post.rb

class Post < ApplicationRecord self.ignored_columns = [:title] end

The columns specified in ignored_columns are excluded from the schema reading process in terms of implementation.

activerecord/lib/active_record/model_schema.rb

def load_schema! unless table_name raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name=" end columns_hash = connection.schema_cache.columns_hash(table_name) columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?

Release this up to this point once and reflect it in the production environment and so on.

Delete a column (Create a migration file to delete a column and update schema.rb)

You can generate a migration file with the following command:

bundle exec rails generate migration クラス名 カラム名:データ型

So this time I used bundle exec rails generate migration RemoveTitleFromPosts title:string to generate the following migration file.

db/migrate/20220629204906_remove_title_from_posts.rb

class RemoveTitleFromPosts < ActiveRecord::Migration[6.1] def change remove_column :posts, :title, :string end end

Some articles are written using the change method, while others use the up and down methods, but either should be fine.

It seems that it is necessary to provide type information when using change in order to avoid failure during rollback.

remove_columnは、第3引数でカラムの型を指定すれば逆進可能になります。この場合、元のカラムオプションも指定しておくこと。そうしないと、マイグレーションの逆進時にカラムを再作成できなくなります。
remove_column can be reversed by specifying the column type in the third argument. In this case, the original column options must also be specified. Otherwise, the column will not be re-created during migration reversion.

Run bundle exec rails db:migrate to migrate and confirm that schema.rb has been updated.

If there are any foreign keys or indexes set up, they should also be deleted.

Remove ignored_columns

I will delete the added ignored_columns.

app/models/post.rb

class Post < ApplicationRecord - self.ignored_columns = [:title] end

Please release the information so far.

Before the Rails application code is released to the web server as part of the deployment configuration, it is necessary to ensure that the database migration is completed. After this, you can summarize and release 4. Delete columns.

If not, it seems better to release 4. Delete columns and 5. Delete ignored_columns separately.

This is completed.

Reference

Table of Contents