Posted at

mark_for_destructionで特定の子モデルを一括削除する


概要

#mark_for_destruction を使うと、親要素を保存するタイミングで特定の子モデルをまとめて削除できる。

検証環境は以下の通り。


  • Ruby On Rails: 5.2.1

  • Ruby: 2.5.1

  • MySQL: Ver 14.14 Distrib 5.7.24


利用例

例として、DeckモデルとCardモデルが「Deck has many Cards」な関係にあるとする(カードデッキをイメージ)。

親モデル側(ここではDeck)に autosave: true を設定しておかないといけないので注意。


deck.rb

class Deck

has_many :cards, autosave: true
end


card.rb

class Card

belongs_to :deck
end

次に、1つのDeckに対して複数のCard(card1 ~ card3)を作成する。

deck = Deck.create(name: 'my deck')

deck.cards.create(name: 'card1')
deck.cards.create(name: 'card2')
deck.cards.create(name: 'card3')

ここで、例として card1card3 を削除したいとしよう。

対象のCardに対して #mark_for_destruction を呼び出した上で、Deckを保存する。そうすると、#mark_for_destruction をつけたCardが全て削除される

deck.cards.first.mark_for_destruction # card1

deck.cards.last.mark_for_destruction # card3
deck.save
# (0.2ms) BEGIN
# Card Destroy (0.4ms) DELETE FROM `cards` WHERE `cards`.`id` = 2
# Card Destroy (0.5ms) DELETE FROM `cards` WHERE `cards`.`id` = 4
# (0.3ms) COMMIT
# => true

deck.cards.count
# => 1


参考リンク