Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails 6.1: 関連付けをバックグラウンド削除する「dependent: :destroy_async」(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。

Rails 6.1: 関連付けをバックグラウンド削除するdependent: :destroy_async(翻訳)

Railsに組み込まれているdependent:オプションを使うと、dependent:に指定したオーナーがdestroyされたときに関連付けられたレコードをどうするかを指定できます。

従来のRailsでは、dependent::destroy:delete_allなどの値を渡せます。

:destroy:delete_allは互いによく似通っていますが、唯一の違いは、:delete_allは関連付けられたオブジェクトをすべて削除するときにコールバックを一切実行しないことです。

訳注: dependent:オプションに:destroy:delete_allがあるのはhas_many関連付けの場合です。

has_many
dependent:削除系オプション
:destroyまたは:delete_all
(他のオプションは省略)
belongs_to
dependent:削除系オプション
:destroyまたは:delete
(他のオプションは省略)
has_one
dependent:削除系オプション
:destroyまたは:delete
(他のオプションは省略)

オブジェクトの関連付けが何層にも積み重なっている大規模なシステムでは、削除のカスケードが失敗することがあります。あるモデルが持つ関連付けが削除されると、それによって他の削除もトリガーされて、複雑なツリーの下まで続く可能性があります。このようなカスケード削除は非常に時間がかかるので、サーバーでタイムアウトエラーが発生するとロールバックする可能性があります。

解決方法: dependent:オプションに:destroy_asyncを指定する

Rails 6.1から、関連付けでdependent:の値に:destroy_asyncを渡せるサポートが追加されました(#40157)。

AuthorモデルとBookモデルがあるとします。

以下のように、has_many :books関連付けのdependent:オプションに:destroy_asyncという値を渡していることにご注目ください。

class Author < ApplicationRecord
  has_many :books, dependent: :destroy_async
end
class Book < ApplicationRecord
  belongs_to :author
end

たとえばidが1のauthorがBooksモデルの4つのid(1, 2, 3, 4)に関連付けられているとすると、idが1のauthorを削除したときにRailsが以下のようなジョブを1件作成します。

Performing ActiveRecord::DestroyAssociationAsyncJob (Job ID: 40d5c0cf-ed73-493b-8964-541ae6f1960f) from Async(active_record_destroy) enqueued at 2020-11-16T15:27:00Z with arguments: {:owner_model_name=>"Author", :owner_id=>1, :association_class=>"Book", :association_ids=>[1, 2, 3, 4], :association_primary_key_column=>:id,

このジョブが実行されると、Authorモデルにあるそのレコードがデータベースから削除され、以下のようなログが出力されます。

Performed ActiveRecord::DestroyAssociationAsyncJob (Job ID: 40d5c0cf-ed73-493b-8964-541ae6f1960f) from Async(active_record_destroy) in 21.8ms

関連記事

Rails 6.1: CHECK制約のサポートをマイグレーションに追加(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。