Skip to content

Instantly share code, notes, and snippets.

@ichi
Last active August 29, 2015 14:18
Show Gist options
  • Select an option

  • Save ichi/3e6dfc4f2e16f3077979 to your computer and use it in GitHub Desktop.

Select an option

Save ichi/3e6dfc4f2e16f3077979 to your computer and use it in GitHub Desktop.
# USAGE:
# rails g migration add_deleted_at_to_hoge_model deleted_at:datetime
#
# class HogeModel
# extend Extensions::SoftDeletable
# soft_deletable
# end
#
#
# hoge.destroy_softly # or hoge.destroy_softly!
# hoge.restore_soft_delete # or hoge.restore_soft_delete
#
# hoge.deleted?
# hoge.living?
#
# HogeModel.living
# HogeModel.deleted
#
module Extensions
module SoftDeletable
def soft_deletable(column: :deleted_at,
soft_delete_method_name: :destroy_softly, restore_method_name: :restore_soft_delete,
soft_deleted_scope: :deleted, without_soft_deleted_scope: :living)
Initializers.create_column_name_accessor(self, column)
Initializers.create_method_name_accessor(self, soft_delete_method_name, restore_method_name)
Initializers.create_callbacks(self)
Initializers.create_instance_methods(self, soft_deleted_scope, without_soft_deleted_scope)
Initializers.create_scopes(self, soft_deleted_scope, without_soft_deleted_scope)
end
module Initializers
def self.create_column_name_accessor(klass, column)
klass.class_eval do
define_singleton_method(:soft_delete_column) { column }
delegate :soft_delete_column, to: :class
end
end
def self.create_method_name_accessor(klass, soft_delete_method_name, restore_method_name)
klass.class_eval do
define_singleton_method(:soft_delete_method_name) { soft_delete_method_name }
define_singleton_method(:restore_method_name) { restore_method_name }
delegate :soft_delete_method_name, :restore_method_name, to: :class
end
end
def self.create_callbacks(klass)
klass.class_eval do
define_model_callbacks soft_delete_method_name
define_model_callbacks restore_method_name
end
end
def self.create_instance_methods(klass, soft_deleted_scope, without_soft_deleted_scope)
klass.class_eval do
define_method "#{soft_delete_method_name}!" do
run_callbacks(soft_delete_method_name) { touch soft_delete_column; self }
end
define_method soft_delete_method_name do
!! send("#{soft_delete_method_name}!") rescue nil
end
define_method "#{restore_method_name}!" do
run_callbacks(restore_method_name) { update_column soft_delete_column, nil; self }
end
define_method restore_method_name do
!! send("#{restore_method_name}!") rescue nil
end
define_method "#{soft_deleted_scope}?" do
send("#{soft_delete_column}?")
end
define_method "#{without_soft_deleted_scope}?" do
!send("#{soft_delete_column}?")
end
end
end
def self.create_scopes(klass, soft_deleted_scope, without_soft_deleted_scope)
klass.class_eval do
scope soft_deleted_scope, ->{ where.not(soft_delete_column => nil) }
scope without_soft_deleted_scope, ->{ where(soft_delete_column => nil) }
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment