dependent 関連元が削除された時の関連先に対する操作を指定する

使用可能な関連付け

  • belongs_to
  • has_many
  • has_one

対となる関連に指定するオプション

なし

概要

関連元が削除された時の関連先に対する操作を指定する。

関連ごとに指定できるオプションが異なる。

未指定またはdependent: nil

  • belongs_to
  • has_many
  • has_one

で利用可能。

何もしない。

dependent: :destroy

  • belongs_to
  • has_many
  • has_one

で利用可能。

指定した関連先に対してdestroyを実行する。destroyなのでコールバックなども実行される。

dependent: :delete

  • belongs_to
  • has_one

で利用可能。

指定した関連先に対してdeleteを実行する。deleteなのでコールバックなどは実行されずにDELETE文が実行される。

dependent: :delete_all

  • has_many

で利用可能。

指定した関連先に対してdeleteを実行する。deleteなのでコールバックなどは実行されずにDELETE文が実行される。

dependent: :destroy_async

  • belongs_to
  • has_many
  • has_one

で利用可能。

関連先に対してdestroyを実行するJobを登録する。Active Jobが必要。同一トランザクションで削除する必要がなく、パフォーマンスなどの理由で非同期に削除したい場合に使う。外部キー制約が指定されている場合は同一トランザクションで削除しないといけないため、このオプションは利用できない。

dependent: :nullify

  • has_many
  • has_one

で利用可能。

関連先の外部キーにNULLを設定する。ポリモーフィック関連の場合はtypeカラムもNULLにする。コールバックは実行されない。

dependent: :restrict_with_exception

  • has_many
  • has_one

で利用可能。

関連先が存在している場合はActiveRecord::DeleteRestrictionError例外を投げる。

dependent: :restrict_with_error

  • has_many
  • has_one

で利用可能。

関連先が存在している場合はerrorsにエラーが追加される。

スコープとの組み合わせ

class Blog < ApplicationRecord
  has_many :entries, -> { where(published: true) }, dependent: :destroy
end

上記のようにスコープと組み合わせている場合、スコープで絞り込まれた対象だけがdependentオプションの対象となる。なので、上記の例ならpublished: falseなEntryがあれば外部キーもそのままの状態で残り続けてしまう。

双方向関連における belongs_to :..., dependent: ...

class Blog < ApplicationRecord
  has_many :entries
end

class Entry < ApplicationRecord
  belongs_to :blog, dependent: :destroy
end

上記のような実装をした状態で、Entry.last.destroyを実行した場合、Entry.lastEntry.last.blogの2レコードは消えるが、Entry.last以外のEntry.last.blog.entriesのレコードは残り続けてしまう。

このような結果を避けたい場合は、has_manyの方にもdependentオプションを指定する。

class Blog < ApplicationRecord
  has_many :entries, dependent: :destroy
end

class Entry < ApplicationRecord
  belongs_to :blog, dependent: :destroy
end

throughオプションとの組み合わせ

検証してみたが挙動がよくわからない。