Safely delete columns in a Ruby on Rails app in production
投稿日: 2024/06/25
更新日: 2024/07/01
This article is a translation of the following article.
Procedure
- Fix all the code using the column to be deleted
- Add ignored_columns to the column
- Release the changes made so far
- Delete the column (Create a migration file to delete the column and update schema.rb)
- Remove ignored_columns
- 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.