🏓

Rails で既存テーブルに STI を適用する時に気をつけること

2024/12/19に公開

Rails の STI (Single Table Inheritance) は、1つのテーブルで複数のモデルを管理できる便利な機能です。しかし、既存のテーブルを STI に移行する際には注意が必要です。今回は、実際に遭遇した問題とその解決策について共有します。

問題が発生した状況

既存のテーブルに STI を導入するため、以下の変更を1回のリリースで行おうとしました。

  • type カラムの追加
  • サブクラスの追加

デプロイの流れは以下のようになっていました

  • データベースのマイグレーション実行(db:migrate)
  • Rails アプリケーションの再起動

この時、マイグレーション実行から Rails の再起動までの間に ActiveRecord::SubclassNotFound エラーが発生しました。

なぜ問題が起きたのか

Rails では、テーブルに type カラムが存在すると、自動的に STI として扱われます。つまり、type カラムを追加した時点で、Rails はそのカラムに対応するサブクラスを探しにいきます。しかし、サブクラスの定義がまだデプロイされていない状態だったため、エラーが発生してしまいました。

どうすればよかったか

この問題を避けるためには、リリースを2段階に分ける必要がありました。

Step 1: サブクラスの追加と inheritance_column の無効化

最初のリリースでは

  • サブクラスを追加する
  • inheritance_column を nil に設定し、STI を一時的に無効化する

Step 2: STI の有効化

次のリリースで

  • データベースのマイグレーションを実行
  • inheritance_column の設定を削除し、STI を有効化する

この設定方法はRailsガイドにバッチリ記載がありました

https://railsguides.jp/association_basics.html#継承カラムを無効にする

学び

この経験から学んだ重要な点は

  • 機能テストだけでなく、デプロイプロセス自体も考慮に入れる必要がある
  • データベースの変更を伴う機能追加は、段階的なリリースを検討する
  • Rails の STI の仕組みについて、より深い理解が必要

今回は幸いにも影響が小さかったものの、より重要なテーブルであれば大きな問題になっていた可能性があります。既存のテーブルでSTIを使いたいケースはそう多くないとは思いますが、似たような状況に遭遇した方の参考になれば幸いです。

Hacobell Developers Blog

Discussion