A few years ago, I described how to combine acts_as_paranoid and acts_as_versioned in order to make deleted records end up in your versioning tables.
In order to do the same thing under Rails 3, I had to make a few adjustments. First of all, you need the rails3_acts_as_paranoid gem, which is a total rewrite of acts_as_paranoid for rails 3. Add these lines to your Gemfile:
gem 'rails3_acts_as_paranoid' gem 'acts_as_versioned'
Then put a file in config/initializers with these contents:
module ActiveRecord module Acts module Versioned def acts_as_paranoid_versioned(options = {}) acts_as_paranoid acts_as_versioned options # Override the destroy method. We want deleted records to end up in the versioned table, # not in the non-versioned table. self.class_eval do def destroy() with_transaction_returning_status do run_callbacks :destroy do # call the acts_as_paranoid delete function self.class.delete_all(:id => self.id) # get the 'deleted' object tmp = self.class.unscoped.find(id) # run it through the equivalent of acts_as_versioned's # save_version(). We used to call that function but it is a # noop when @saving_version is not set. That only gets done in # a protected function set_new_version(). Easier to just # replicate the meat of the save_version() function here. rev = tmp.class.versioned_class.new clone_versioned_model(tmp, rev) rev.send("#{tmp.class.version_column}=", send(tmp.class.version_column)) rev.send("#{tmp.class.versioned_foreign_key}=", id) rev.save # and finally really destroy the original self.class.delete_all!(:id => self.id) end end end end # protect the versioned model self.versioned_class.class_eval do def self.delete_all(conditions = nil); return; end end end end end end
I wonder if there is a more elegant way to achieve this…
Note: code updated at 2011-05-28 to make sure :dependent => :destroy on has_many associations does the right thing.
I fixed this issue directly, in my acts_as_versioned gem. See “Update”, at https://github.com/mjsommer/acts_as_versioned