require 'active_support/concern'
require 'active_record'
require "acts_as_removable/version"
module ActsAsRemovable
extend ActiveSupport::Concern
module ClassMethods
# Add ability to remove ActiveRecord instances
#
# acts_as_removable
# acts_as_removable column_name: 'other_column_name'
# acts_as_removable with_default_scope: true
#
# ===== Options
#
# * :column_name - A symbol or string with the column to use for removal timestamp.
# * :with_default_scope - A boolean indicating to set a default scope with only active (not removed) records
def acts_as_removable(options = {})
_acts_as_removable_options.merge!(options)
scope :removed, -> {
removed_at_column_name = _acts_as_removable_options[:column_name]
query = where(all.table[removed_at_column_name].not_eq(nil).to_sql)
_removable_where_values(query, removed_at_column_name, all.table[removed_at_column_name].eq(nil).to_sql)
}
scope :actives, -> {
removed_at_column_name = _acts_as_removable_options[:column_name]
query = where(all.table[removed_at_column_name].eq(nil).to_sql)
_removable_where_values(query, removed_at_column_name, all.table[removed_at_column_name].not_eq(nil).to_sql)
}
default_scope -> {where(all.table[_acts_as_removable_options[:column_name]].eq(nil).to_sql)} if _acts_as_removable_options[:with_default_scope]
define_model_callbacks :remove, :unremove
class_eval do
def self.before_remove(*args, &block)
set_callback(:remove, :before, *args, &block)
end
def self.after_remove(*args, &block)
set_callback(:remove, :after, *args, &block)
end
def self.before_unremove(*args, &block)
set_callback(:unremove, :before, *args, &block)
end
def self.after_unremove(*args, &block)
set_callback(:unremove, :after, *args, &block)
end
def removed?
send(self.class._acts_as_removable_options[:column_name]).present?
end
def remove(options = {})
_update_remove_attribute(:remove, Time.now, false, options)
end
def remove!(options = {})
_update_remove_attribute(:remove, Time.now, true, options)
end
def unremove(options = {})
_update_remove_attribute(:unremove, nil, false, options)
end
def unremove!(options = {})
_update_remove_attribute(:unremove, nil, true, options)
end
def _update_remove_attribute(callback, value, with_bang = false, options = {})
self.class.transaction do
run_callbacks callback.to_sym do
send("#{self.class._acts_as_removable_options[:column_name]}=", value)
with_bang ? save!(options) : save(options)
end
end
end
end
end
def _acts_as_removable_options
@_acts_as_removable_options ||= {
column_name: 'removed_at'
}
end
# Delete where statements from query
def _removable_where_values(query, column_name, remove_where)
query = query.with_default_scope if query.respond_to?(:with_default_scope)
query.where_values.delete(remove_where)
query
end
end
end
ActiveRecord::Base.send(:include, ActsAsRemovable)