この頃、論理削除に関する論争があったと思いますが、Railsではacts_as_paranoid, paranoia, kakurenboなど様々な論理削除用gemが登場しており、私もこれらのgemを利用していました。しかし、ActiveRecordのメソッドをオーバーライドするこれらのgemは、Railsのバージョンアップで壊れる可能性があり、メンテナンスされなくなってしまうとこれらのgemの影響でRailsのアップグレードができないということになりかねないため、paranoidを使うのをやめて、kakurenbo-putiを使うように修正中です。
kakurenbo-putiは、ActiveRecordのメソッドを上書きすることなく、機能追加という形で論理削除用のメソッドを入れるという方式のため、安全です。
しかし、既にparanoiaを使っているプロジェクトを修正していく際に、結構ハマりがちです。というかまだ私のプロジェクトでは修正しきれていません。
そこで、どういう対応をしたか忘れないために、メモを書いておこうと思います。
Deviseを使っている場合
paranoiaを使っている場合はdefault_scopeが論理削除ユーザーを排除するように上書きされていたので特に意識することがなかったのですが、kakurenbo-putiの場合は、勝手にdefault_scopeを変更することはないので、自分で設定する必要があります。
Deviseのwikiに書かれていますが、認証部分のメソッドをオーバーライドして、ログイン可能対象ユーザーを絞っておく必要があります。self.without_soft_destroyed
を使っておきます。
class User < ActiveRecord::Base
devise :database_authenticatable,
:registerable,
:timeoutable,
:recoverable,
:rememberable,
:trackable,
:confirmable
soft_deletable column: :deleted_at
# Deviseの認証に関わる箇所
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
self.without_soft_destroyed.where(conditions.to_h).first
end
end
Ancestryを使っている場合
ユーザーに、親ユーザーと子ユーザーを持たせていたので、Ancestryを使っています。
親ユーザーを論理削除したら、子ユーザーも全部論理削除してほしかったのですが、kakurenbo-putiで設定できる親子関係の削除設定は、ほかのテーブル同士の場合なので、Ancestryを使った同一テーブルのものは考慮されていません(当たり前だけど)。
子が削除されたら取得しないように
また、子ユーザーを論理削除した後でも、user.children
を行ったら削除済みの子ユーザーが含まれた結果になります。しかし、childrenを上書きするのも面倒そうな気がしたので、短いメソッドを定義しました。user.live_children
で論理削除を除いた子ユーザーを取得します。
class User < ActiveRecord::Base
def live_children
self.children.without_soft_destroyed
end
end
親が削除されたら子も削除
そして、親ユーザーが削除されたら、子ユーザーを削除するという処理を書いておく必要があります。kakurenbo-putiのコードを読むと、define_model_callbacks :soft_destroy
というのがあるので、これを使いましょう。
class User < ActiveRecord::Base
soft_deletable column: :deleted_at
has_ancestry
set_callback :soft_destroy, :after, :soft_destroy_with_children
def soft_destroy_with_children
if self.root? && self.soft_destroyed?
self.live_children.each do |child|
child.soft_destroy
end
end
end
end
また、Tipsがあったら追加していこうと思います。