LoginSignup
15
12

More than 5 years have passed since last update.

既存プロジェクトでkakurenbo-putiを使うときのtips

Last updated at Posted at 2015-04-07

この頃、論理削除に関する論争があったと思いますが、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を使っておきます。

app/models/user.rb
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で論理削除を除いた子ユーザーを取得します。

app/models/user.rb
class User < ActiveRecord::Base

  def live_children
    self.children.without_soft_destroyed
  end

end

親が削除されたら子も削除

そして、親ユーザーが削除されたら、子ユーザーを削除するという処理を書いておく必要があります。kakurenbo-putiのコードを読むと、define_model_callbacks :soft_destroyというのがあるので、これを使いましょう。

app/models/user.rb
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があったら追加していこうと思います。

15
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
12