Just do IT

思うは招く

Rails の dependent: :restrict_with_exception について調べた

先に結論:

restrict_with_exceptionオプションとは:

  • 親レコードを削除するとき、子レコードがある場合はActiveRecord::DeleteRestrictionErrorが発生して削除できない
  • 子レコードを先に削除しないと、親レコードを削除できないオプションのこと

詳細

Railsdependentオプションとは、親のレコードを削除したとき、子レコードの扱いをどうするか決める機能。

よく見るのはおそらくdependent: :destroyで、親レコードを削除したときには子レコードも一緒に削除するといったもの。

今回はdependentオプションのひとつ、dependent: :restrict_with_exceptionについて学んだ。

参考記事:dependent: :restrict_with_error と :restrict_with_exception の違い - Qiita

:restrict_with_exceptionオプションをつけると、親レコードを削除するとき、子レコードがある場合はActiveRecord::DeleteRestrictionErrorが発生する。つまり削除できない。そのため、子レコードを先に削除しておく実装が必要になる。

たとえば、下記のようなモデル構成の場合。

class Category < ApplicationRecord
  has_many :items, dependent: :restrict_with_exception
end

この場合、item を削除してからじゃないと、category を削除できない。category を先に削除しようとすると、ActiveRecord::DeleteRestrictionError が発生する。

deleteメソッド

ちなみに、destroyメソッドに似たものとして、deleteメソッドがある。destroyはActiveRecordを介するため、関連付けの設定を呼ぶ。

deleteメソッドは、ActiveRecordを介さずに直接SQLを発行する。つまりバリデーションを無視する。また、関連付けされているレコードがあったとしても、そちらは削除されない。

https://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-delete