Rails3で論理削除するプラグイン
Rails3のActiveRecord実装の勉強がてらにRails3専用のレコード論理削除プラグイン 'Millstone' を作成しました。
gem 'millstone'
class User < ActiveRecord millstone # または acts_as_paranoid end User.with_deleted # 削除済みも含めて全部取得 User.only_deleted # 削除済みのみ取得 User.administrators.with_deleted # NamedScopeからも利用できる User.first.comments.with_deleted # 関連からももちろん利用できる User.first.destroy # 論理削除する User.first.destroy! # 物理削除する
- acts_as_paranoidやrails3_acts_as_paranoidと出来る限り同じ振る舞いをするように実装した
- recover系メソッドは未実装
- !!重要!! 3.0.6 未満では動かない・・・orz
- 詳しくは こちら で
つくろうと思った経緯
色々と理由はあるけど、一番の理由は、rails3_acts_as_paranoidに僕が望んでいる以下の機能がなかったから。
- Rails2世代にあった削除済みを含めた関連を取得するオプション
belongs_to :with_deleted => true
- 削除済みも含めて関連のレコードを取得 ( rails3_acts_as_paranoid では関連でwith_deletedを使うとSQLがおかしなことになる。
User.first.associations.with_deleted
rails3_acts_as_paranoid は、Rails2世代のacts_as_paranoidのようにパワフルにはできてない感じだった。READMEにはシンプルにしたって書いてあったしね。
rails3_acts_as_paranoidをfork、拡張しようと頑張ってみたんだけど、「削除済みも含めて関連のレコードを取得」の実装が、default_scopeを生かしつつうまく実装できなかった。。
そこでRails3のActiveRecordの勉強がてらに自作してみることにした。
実装について
Rails3のActiveRecordを見てみると、データベースを操作するようなメソッドは ActiveRecord::Relation に委譲するように実装されていたので、ActiveRecord::Relation を拡張することで対応してみた。
嬉しいことにActiveRecord::Relation#extendingという指定されたモジュールをextendしてくれるメソッドが用意されていたので、論理削除モデルだけに拡張モジュールを組み込むようにすることができた。
拡張モジュールで対応したことは以下の通り。
- 物理削除メソッドを用意した
- 既存の削除メソッドを論理削除に書き換えた
- 検索フラグを用意して、最終的にクエリを発行する際にフラグの状態をみて、検索条件に論理削除の条件を追加するように処理を書き換えた
実装はしてみたものの、拡張しすぎて3.0.0系でも3.0.6未満は動かない始末・・・
バランスって大切だなぁとあらためて思った。
ライブラリを作ることは多々あるけど、Gemとしての公開は初めてです。
よかったら触ってみてください。