This was in a content management project where a site may have many pages. Users were able to delete the page, and I wanted to keep the "activity log" complete. So I could refer to the page, but not show it. "Jim deleted the page 'welcome'", for example. Where welcome is the @page.name.
The page name was unique and I didn't want to do anything too complicated to ensure the names were unique - if there was an existing name already, don't allow another. But, if a deleted page had the name 'Welcome', I didn't want to see a validation error.
This is an easy situation to handle...
First, add a mark_deleted method in the Model.
def mark_deleted
self.deleted_at = Time.now
end
def mark_deleted!
mark_deleted
self.save
end
For the name, set the uniqueness validation to have a scope
validates_uniqueness_of :name, :scope => [:parent_id, :deleted_at]
You'll need to add the deleted_at column via a migration
class AddDeletedAtToObject < ActiveRecord::Migration
def self.up
add_column :objects, :deleted_at, :datetime
end
def self.down
add_column :objects, :deleted_at
end
end
When you call the 'destroy' method in the controller, instead of object.destroy!, call object.mark_deleted!
And when referring to parent.objects, call parent.objects.not_deleted, instead.
scope :not_deleted, where('objects.deleted_at is null')
On issue I had with this approach (using rails3_acts_as_paranoid, but it's the same principle) is that you have to way to getting rid of associations. I have a complex model with associations all around, and I really cannot afford to mess it up. So the only way to remove users in my case is: user.destroy. Calling user.mark_deleted! ends up in a lot of "broken links" (from contacts, likes, etc).
ReplyDeleteOne way would be to have all liked model act[ing]_as_paranoid, but I don't know if destroy works in this case... I am interesed if you have a fix for that