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

運用中のRuby on Railsアプリで安全にカラムを削除する

ruby
rails
postgresql

投稿日: 2024/06/25

手順

  1. 削除するカラムを使ってるコードをすべて修正
  2. ignored_columns をカラムに付ける
  3. ここまでの変更をリリースする
  4. カラムを削除する(カラムを削除するマイグレーションファイルを作成し、schema.rbを更新)
  5. ignored_columns を削除
  6. リリースする

削除するカラムを使ってるコードをすべて修正

実際にカラムを削除する前に、削除予定カラムを使わないようにすべて修正しておきます。

ignored_columns をカラムに付ける

ActiveRecordはスキーマキャッシュでカラム情報をキャッシュしてます。

プロダクション環境などで運用中のサービスに対していきなりカラムを削除すると、削除前のスキーマがキャッシュされてるので、Railsアプリケーション側はすでに削除されたカラムが存在するようにふるまってしまいます。

以下のようにignored_columnsにカラムを追加すると、Railsは該当カラムを無視するようにふるまいます。

app/models/post.rb

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

仕組みとしてはignored_columnsに指定されてるカラムはスキーマを読み込むときに除外される実装になっています。

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?
https://github.com/rails/rails/blob/7-0-stable/activerecord/lib/active_record/model_schema.rb#L581

ここまでを一度リリースして、本番環境などへ反映させます。

カラムを削除する(カラムを削除するマイグレーションファイルを作成し、schema.rbを更新)

以下のようなコマンドでマイグレーションファイルを生成できます。

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

なので今回は bundle exec rails generate migration RemoveTitleFromPosts title:string

db/migrate/20220629204906_remove_title_from_posts.rb

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

のようなマイグレーションファイルを生成しました。
記事によってはchangeメソッドとupdowmメソッドで書かれてる記事がありますがどちらでもよいはずです。

ただ、少なくともchangeで行く場合は型情報を書いてあげないとロールバックに失敗するらしいので必要です。

remove_columnは、第3引数でカラムの型を指定すれば逆進可能になります。この場合、元のカラムオプションも指定しておくこと。そうしないと、マイグレーションの逆進時にカラムを再作成できなくなります。
https://railsguides.jp/active_record_migrations.html#change%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E4%BD%BF%E3%81%86

bundle exec rails db:migrateでマイグレーションしてschema.rbが更新されてるのを確認します。

外部キーやインデックスの設定があればそれも削除されるはずです。

ignored_columns を削除

追加したignored_columnsを削除します。

app/models/post.rb

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

リリースします。

デプロイの構成としてRailsアプリケーションのコードがWebサーバーにリリースされる前に、DBのマイグレーションが完了することが保証されていなければ4. カラムを削除するとまとめてリリースできます。

そうでなければ4. カラムを削除する5. ignored_columns を削除は分けてリリースしたほうがよさそうです。

これで完了です。

参考

yosi

Noh を作ってるエンジニア。

目次