Today I had an interesting feature request to implement: Get rid of all deletions and replace them with a deleted
flag in the DB.
It's the usual story: Nobody really does deletes but rather everything is put into the DB in case it's needed at some later point. Unfortunately I didn't know about this particular feature until after I had finished most of the coding for the Rails application so going through the code and removing all destroy code from controllers was pretty much out of the question.
Instead I remembered reading about Modules in Ruby and how they can bolt on functionality to Classes.
Turns out it's totally trivial to remove deletion from Rails Models with 10 odd lines of code in a completely transparent an unobtrusive way:
module NotDeleteable def destroy unless self.respond_to? :deleted raise MissingMigrationException endThis will override the default destroy/delete method provided byself.update_attribute :deleted, true end
def delete self.destroy end
def self.included(base) base.class_eval do default_scope where( :deleted => false ) end end end
class MissingMigrationException < Exception def message "Model is lacking the deleted boolean field for NotDeleteable to work" end end
ActiveRecord::Base
and also install a default_scope into the Model class so Rails will by default append WHERE deleted = false
to all SQL queries made through the ActiveRecord Query Interface
You use this by simply including this module inside your Model class:
class User < ActiveRecord::Base include NotDeleteable endDid I mention that I really like Ruby?
Word of warning:
I have no clue if I am breaking :dependant => :destroy
on ActiveRecord relations in any way, but I suspect it should still be alright.
Update: The original code had an issue where you could not mark a record that is invalid as deleted. This was due to the fact that I was using save
instead of update_attribute.