NULL禁止制約を後付けする際の注意点
データメンテについて
すでにあるカラムをNULL禁止にしようとする際の注意点を教えて頂いたので、以下にまとめます。
参考コード1
まず最初に記述したコード
class ChangeColumnToAllowNull < ActiveRecord::Migration[6.1] def up change_column :comments, :user_id, :integer, null: true end def down change_column :comments, :user_id, :integer, null: false end end
null: falseに変更しようとしています。
以下指摘
down のときのようにあとから NULL 禁止制約をつける場合、対象カラムが NULL であるレコードがすでに存在しているとマイグレーション適用時にエラーになってしまいます。
そして、本番運用しているサービスだと大抵の場合はそういうデータが存在しているものなので、制約をつける前に、何かしらのデータを入れる必要があります(これをデータメンテと呼んだりします)。今回の場合はこんな感じになります。def down
# id: 1 のユーザーに無理やり関連付ける
execute "UPDATE comments SET user_id = 1 WHERE user_id IS NULL"
change_column :comments, :user_id, :integer, null: false
end
例として id: 1 のユーザーに無理やり関連付けていますが、これはあくまで一例です。
すでに運用しているサービスの場合には、チームで話し合ってもうちょっと現実的な手段を取ります。
ご指摘の通り本番サービスを意識すると、こういったそもそものデータ基盤自体の変更って気軽にできませんので、慎重に検討すべき事由です。
参考コード2
またカラムの変更方法は、下記の様にも書けます。
変更したコードが下記。
だいぶスッキリ!
class ChangeColumnToAllowNull < ActiveRecord::Migration[6.1] def change change_column_null(:comments, :user_id, true) end end
class ChangeColumnToAllowNull < ActiveRecord::Migration[6.1] def change # 実装当時のチーム協議の結果、ロールバック時は、退会済みユーザのコメントはダミーのユーザアカウントを用意してそれに関連づけてしまう # 協議ログ: https://hogehoge-log.com/xxxxxx change_column_null(:comments, :user_id, true, 2) end end