acts_as_versionedとacts_as_paranoid
acts_as_versionedはモデルの変更履歴をバージョンテーブルに取っておいてくれて、acts_as_paranoidはモデルの削除を物理削除じゃなく論理削除にしてくれるので、一緒に使えば変更を完全に取っておけるんじゃね?と思ったんだけどどうもうまくいかない。
acts_as_paranoidを使うと、元のモデルは論理削除されるんだけど、バージョンテーブルの方が物理削除されてしまう。
てことで、解法1
class User < ActiveRecord::Base acts_as_paranoid acts_as_versioned :association_options => {:dependent => nil} end
acts_as_versionedの宣言時に上記のようなオプションを渡してやれば、モデルが削除されてもバージョンテーブル側は残り続ける。
ただしこの場合、acts_as_versionedは論理削除を更新とは見なしてくれないので「削除された」という情報はバージョンテーブルには残らない。
てことで、解法2
class UserVersions < ActiveRecord::Base acts_as_paranoid :with => 'versions_deleted_at' end class User < ActiveRecord::Base acts_as_paranoid acts_as_versioned :association_options => {:class_name => 'UserVersions', :dependent => :destroy} end
バージョンテーブルにもacts_as_paranoidを設定して論理削除にする。これで削除されたことを後で捕捉できる。
ただし罠がいくつかあるので注意。
- 元のテーブルもacts_as_paranoidしているのでバージョンテーブルではdeleted_atというカラム名は使えない。上の例のように:withオプションで異なるカラム名を設定するか、acts_as_versionedのnon_versioned_columnsを設定する
# 別解 class User < ActiveRecord::Base acts_as_paranoid acts_as_versioned :association_options => {:class_name => 'UserVersions', :dependent => :destroy} self.non_versioned_columns << 'deleted_at' end
- acts_as_versionedはバージョンモデルとしてUser::Version(どこで宣言されてるんだろう?)を使うことを仮定しているので、:class_nameオプションでUserVersionsモデルを使用するように設定する
- acts_as_versionedは元モデルが削除されたときにdelete_allを使用してバージョンモデルを削除するけどそれだと物理削除されてしまうので、:dependentオプションでdestroyを使うように設定する
ただし、このやり方でも論理削除は更新じゃないので、モデル削除時にバージョンエントリが追加されるわけではない。
てことで、解法3
...は思いつきませんでした。