概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Rails 6.1 adds support for destroying dependent associations in the background | Saeloun Blog
- 原文公開日: 2020/11/18
- 著者: Prasad Walvekar
- サイト: Saeloun Blog | Ruby on Rails Consulting Company based in San Francisco and Boston
日本語タイトルは内容に即したものにしました。
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