🤖

acts_as_paranoidをdiscardへ移行する

2021/07/12に公開

業務にて、acts_as_paranoidを使って論理削除を実装していたのをdiscardへ置き換えたので記しておきます。

・acts_as_paranoid
https://github.com/ActsAsParanoid/acts_as_paranoid
・discard
https://github.com/jhawthorn/discard

acts_as_paranoidはactiveRecordのdestroyメソッドを上書きしているのですが、ほかのgemとの組み合わせにより消したくないレコードが消えてしまう状況になってしまいました。
そのためacts_as_paranoidを脱し、元々のメソッドを上書きしていない論理削除のgemとしてdiscardを使うことになりました。

discardはdestroyメソッドの上書きではなく、該当カラムのupdate処理のようです。

以下、今回行った対応。

deleted_atカラムをdiscardへ流用

discardは論理削除判定に使うカラムを指定することができます。
https://github.com/jhawthorn/discard#custom-column
deleted_atを指定することでacts_as_paranoid用に用意したdeleted_atカラムをそのまま使うことができます。

class Hoge < ApplicationRecord
  include Discard::Model
  self.discard_column = :deleted_at
  

destroyメソッドをdiscardメソッドへ

@user.destroy

など、destroyやdestroy!していたところをdiscard, discard!などに置き換えます。
discard_allなども。使っているところを検索して置き換えました。

scope

with_deleted, only_deletedなscopeが無くなるので、

scope :with_deleted, -> { with_discarded }
scope :only_deleted, -> { with_discarded.discarded }

discardをラップすることで流用しました。

deleted?メソッド

deleted?メソッドが無くなるのでdiscardのメソッドをラップすることで対応しました。
Modelにインスタンスメソッドとして

def deleted?
  discarded?
end

を生やし、内部でdiscarded?を呼んでいます。

dependent: :destroy対応

dependent: :destroyなど削除系で子のレコードを削除していたところも対応が必要でした。
after_discard :destroy_childrenなどを設定し、
destroy_childrenメソッドの中で明示的に子のレコードを削除しました。

コールバック対応

https://github.com/jhawthorn/discard#callbacks
before_destroy -> before_discard
after_destroy -> after_discard
に置き換えて対応、

validates_as_paranoid

validates_as_paranoid
validates_uniqueness_of_without_deleted :email

これらも使えなくなるので対応が必要でした。

やっていることはdeleted_atがnilの条件を追加しているだけなので、

validates_uniqueness_of :email, conditions: -> { where(deleted_at: nil) }

に置き換えました。

acts_as_paranoid
https://github.com/ActsAsParanoid/acts_as_paranoid/blob/v0.6.3/lib/acts_as_paranoid/validations.rb#L18

discardのissueに
https://github.com/jhawthorn/discard/issues/37
があったのでこの対応で大丈夫そう。

注意

destroydiscardへ置き換えましたが、二つはreturnする値が異なります。
destroyはインスタンスを返すのに対して、discardはbooleanを返します。
https://github.com/jhawthorn/discard/blob/f391785f5d9898d6ce67cee0b9929051e1b5bb44/lib/discard/model.rb#L118

具体的には

hoge.destroy.reload

とテストコードで書いているところがあったのを

hoge.discard
hoge.reload

と置き換えました。

終わり

Railsの元々のメソッドなどをオーバーライドするようなgemは気をつけたい。

Discussion