Skip to content

Commit

Permalink
Implement :dependent_recovery_window option
Browse files Browse the repository at this point in the history
  • Loading branch information
wioux authored and bluej100 committed Apr 22, 2015
1 parent ceb0141 commit d5b8f27
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 6 deletions.
26 changes: 20 additions & 6 deletions lib/paranoia.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

module Paranoia
@@default_sentinel_value = nil
@@default_dependent_recovery_window = 120

# Change default_sentinel_value in a rails initilizer
def self.default_sentinel_value=(val)
Expand All @@ -12,6 +13,10 @@ def self.default_sentinel_value
@@default_sentinel_value
end

def self.default_dependent_recovery_window
@@default_dependent_recovery_window
end

def self.included(klazz)
klazz.extend Query
klazz.extend Callbacks
Expand Down Expand Up @@ -66,7 +71,7 @@ def self.extended(klazz)
def destroy
transaction do
run_callbacks(:destroy) do
result = touch_paranoia_column
result = touch_paranoia_column unless destroyed?
if result && ActiveRecord::VERSION::STRING >= '4.2'
each_counter_cached_associations do |association|
foreign_key = association.reflection.foreign_key.to_sym
Expand All @@ -87,16 +92,20 @@ def delete
end

def restore!(opts = {})
opts.merge!(:recovery_window => paranoia_dependent_recovery_window)
self.class.transaction do
run_callbacks(:restore) do
# Fixes a bug where the build would error because attributes were frozen.
# This only happened on Rails versions earlier than 4.1.
noop_if_frozen = ActiveRecord.version < Gem::Version.new("4.1")
deleted_at = send(paranoia_column)
if (noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen
write_attribute paranoia_column, paranoia_sentinel_value
update_column paranoia_column, paranoia_sentinel_value
end
restore_associated_records if opts[:recursive]
if opts[:recursive]
restore_associated_records(deleted_at, opts[:recovery_window])
end
end
end

Expand Down Expand Up @@ -125,7 +134,7 @@ def touch_paranoia_column

# restore associated records that have been soft deleted when
# we called #destroy
def restore_associated_records
def restore_associated_records(deleted_at, window)
destroyed_associations = self.class.reflect_on_all_associations.select do |association|
association.options[:dependent] == :destroy
end
Expand All @@ -136,9 +145,12 @@ def restore_associated_records
unless association_data.nil?
if association_data.paranoid?
if association.collection?
association_data.only_deleted.each { |record| record.restore(:recursive => true) }
x = association_data.only_deleted.
where("#{association.quoted_table_name}.#{paranoia_column} < ?", deleted_at + window).
where("#{association.quoted_table_name}.#{paranoia_column} > ?", deleted_at - window).
each { |record| record.restore(:recursive => true) }
else
association_data.restore(:recursive => true)
association_data.restore(:recursive => true, :recovery_window => window)
end
end
end
Expand Down Expand Up @@ -194,7 +206,9 @@ def really_destroy!
end

include Paranoia
class_attribute :paranoia_column, :paranoia_sentinel_value
class_attribute :paranoia_column, :paranoia_sentinel_value, :paranoia_dependent_recovery_window

self.paranoia_dependent_recovery_window = options[:dependent_recovery_window] || Paranoia.default_dependent_recovery_window

self.paranoia_column = (options[:column] || :deleted_at).to_s
self.paranoia_sentinel_value = options.fetch(:sentinel_value) { Paranoia.default_sentinel_value }
Expand Down
26 changes: 26 additions & 0 deletions test/paranoia_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ def setup
end
end

def with_stubbed_current_time(value, &block)
metaclass = Time.instance_eval{ class << self; self; end }
metaclass.send(:alias_method, :__original_time_now, :now)
metaclass.send(:define_method, :now){ value }
begin
block.call
ensure
metaclass.send(:undef_method, :now)
metaclass.send(:alias_method, :now, :__original_time_now)
metaclass.send(:undef_method, :__original_time_now)
end
end

def test_plain_model_class_is_not_paranoid
assert_equal false, PlainModel.paranoid?
end
Expand Down Expand Up @@ -490,6 +503,7 @@ def test_restore_with_associations
parent = ParentModel.create
first_child = parent.very_related_models.create
second_child = parent.non_paranoid_models.create
third_child = parent.very_related_models.create

parent.destroy
assert_equal false, parent.deleted_at.nil?
Expand All @@ -512,6 +526,18 @@ def test_restore_with_associations
assert_equal true, parent.reload.deleted_at.nil?
assert_equal true, first_child.reload.deleted_at.nil?
assert_equal true, second_child.destroyed?

with_stubbed_current_time(Time.at(0)) do
first_child.destroy
end
with_stubbed_current_time(Time.at(3600)) do
parent.destroy
end
ParentModel.restore(parent.id, :recursive => true, :recovery_window => 5.minute)
assert_equal true, parent.reload.deleted_at.nil?
assert_equal false, first_child.reload.deleted_at.nil?
assert_equal true, second_child.destroyed?
assert_equal true, third_child.reload.deleted_at.nil?
end

# regression tests for #118
Expand Down

0 comments on commit d5b8f27

Please sign in to comment.