Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
real delete when no relation (dependent on acts_as_pranoid)
# lib/active_record/real_delete_discreetly.rb
module RealDeleteDiscreetly
extend ActiveSupport::Concern
def delete_discreetly
relation_exist = false
self.class.confirm_relations.each do |confirm_relation|
if destroyed_by_association
if destroyed_by_association.active_record == confirm_relation.to_s.classify.constantize
relation_exist = false
break
end
else
if reflection = self.class.reflections[confirm_relation].presence
send_method = case reflection.macro
when :has_many
:exists?
else
:present?
end
if send(confirm_relation).send(send_method)
relation_exist = true
break
end
else
raise ArgumentError, "#{confirm_relation} is not Reflection"
end
end
end
unless relation_exist
self.class.delete_all!(self.class.primary_key.to_sym => id)
end
end
module ClassMethods
def real_delete_discreetly(options = {})
class_attribute :confirm_relations
self.confirm_relations = options.delete(:confirm_relations)
acts_as_paranoid options
after_destroy :delete_discreetly
end
end
end
# spec support
shared_examples_for 'real delete discreetly' do |opts|
let(:base_instance) { opts[:base_instance] }
let(:confirm_relations) { opts[:confirm_relations] }
let(:paranoid_column) { opts[:paranoid_column] || :delete_flag }
let(:paranoid_column_type) { opts[:paranoid_column_type] || :boolean }
before do
@model = base_instance.dup
@model.save
case paranoid_column_type.to_sym
when :boolean
@from = false
@to = true
else
time = Time.now
Time.stub(:now).and_return(time)
@from = nil
@to = time
end
end
context 'relation exists' do
before do
confirm_relation = confirm_relations.first
case @model.class.reflections[confirm_relation].macro
when :has_many
@model.send(confirm_relation).send(:build)
else
@model.send("build_#{confirm_relation}")
end
end
it 'soft deleted' do
expect { @model.destroy }.to change { @model.send(paranoid_column) }.from(@from).to(@to)
end
it 'not real deleted' do
expect { @model.destroy }.to change(@model.class.unscoped, :count).by(0)
end
end
context 'when relation not exists' do
it 'real deleted' do
expect { @model.destroy }.to change(@model.class.unscoped, :count).by(-1)
end
end
end
# Usage
## in Model
class UserProfile < ActiveRecord::Base
belongs_to :user
real_delete_discreetly column: :del_flg, column_type: 'boolean', confirm_relations: [:user]
end
## rspec
require 'rails_helper'
RSpec.describe UserProfile, type: :model do
include_examples 'real delete discreetly',
base_instance: UserProfile.create(user_id: nil_or_exist_id),
confirm_relations: [:user]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.