Let\'s keep this simple. Let\'s say I have a User
model and a Post
model:
class User < ActiveRecord::Base
# id:integer name:
I usually use a field named deleted_at
for this case:
class Post < ActiveRecord::Base
scope :not_deleted, lambda { where(deleted_at: nil) }
scope :deleted, lambda { where("#{self.table_name}.deleted_at IS NOT NULL") }
def destroy
self.update_attributes(deleted_at: DateTime.current)
end
def delete
destroy
end
def deleted?
self.deleted_at.present?
end
# ...
# lib/extensions/act_as_fake_deletable.rb
module ActAsFakeDeletable
# override the model actions
def destroy
self.update_attributes(deleted_at: DateTime.current)
end
def delete
self.destroy
end
def undestroy # to "restore" the file
self.update_attributes(deleted_at: nil)
end
def undelete
self.undestroy
end
# define new scopes
def self.included(base)
base.class_eval do
scope :destroyed, where("#{self.table_name}.deleted_at IS NOT NULL")
scope :not_destroyed, where(deleted_at: nil)
scope :deleted, lambda { destroyed }
scope :not_deleted, lambda { not_destroyed }
end
end
end
class ActiveRecord::Base
def self.act_as_fake_deletable(options = {})
alias_method :destroy!, :destroy
alias_method :delete!, :delete
include ActAsFakeDeletable
options = { field_to_hide: :content, message_to_show_instead: "This content has been deleted" }.merge!(options)
define_method options[:field_to_hide].to_sym do
return options[:message_to_show_instead] if self.deleted_at.present?
self.read_attribute options[:field_to_hide].to_sym
end
end
end
Usage:
class Post < ActiveRecord::Base
act_as_fake_deletable
Overwriting the defaults:
class Book < ActiveRecord::Base
act_as_fake_deletable field_to_hide: :title, message_to_show_instead: "This book has been deleted man, sorry!"
Boom! Done.
Warning: This module overwrite the ActiveRecord's destroy
and delete
methods, which means you won't be able to destroy your record using those methods anymore. Instead of overwriting you could create a new method, named soft_destroy
for example. So in your app (or console), you would use soft_destroy
when relevant and use the destroy
/delete
methods when you really want to "hard destroy" the record.