Commit a95a67f0 by Rémi Prévost Committed by Ryan Bigg

Add :recursive option on restore to restore associations

Fixes #91
parent d2814b3a
...@@ -16,11 +16,11 @@ module Paranoia ...@@ -16,11 +16,11 @@ module Paranoia
end end
alias :deleted :only_deleted alias :deleted :only_deleted
def restore(id) def restore(id, opts = {})
if id.is_a?(Array) if id.is_a?(Array)
id.map { |one_id| restore(one_id) } id.map { |one_id| restore(one_id, opts) }
else else
only_deleted.find(id).restore! only_deleted.find(id).restore!(opts)
end end
end end
end end
...@@ -52,8 +52,13 @@ module Paranoia ...@@ -52,8 +52,13 @@ module Paranoia
delete_or_soft_delete delete_or_soft_delete
end end
def restore! def restore!(opts = {})
run_callbacks(:restore) { update_column paranoia_column, nil } ActiveRecord::Base.transaction do
run_callbacks(:restore) do
update_column paranoia_column, nil
restore_associated_records if opts[:recursive]
end
end
end end
def destroyed? def destroyed?
...@@ -78,6 +83,22 @@ module Paranoia ...@@ -78,6 +83,22 @@ module Paranoia
touch(paranoia_column) touch(paranoia_column)
end end
end end
# restore associated records that have been soft deleted when
# we called #destroy
def restore_associated_records
destroyed_associations = self.class.reflect_on_all_associations.select do |association|
association.options[:dependent] == :destroy
end
destroyed_associations.each do |association|
association = send(association.name)
if association.paranoid?
association.only_deleted.each { |record| record.restore(:recursive => true) }
end
end
end
end end
class ActiveRecord::Base class ActiveRecord::Base
......
...@@ -18,6 +18,7 @@ ActiveRecord::Base.connection.execute 'CREATE TABLE employers (id INTEGER NOT NU ...@@ -18,6 +18,7 @@ ActiveRecord::Base.connection.execute 'CREATE TABLE employers (id INTEGER NOT NU
ActiveRecord::Base.connection.execute 'CREATE TABLE employees (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)' ActiveRecord::Base.connection.execute 'CREATE TABLE employees (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
ActiveRecord::Base.connection.execute 'CREATE TABLE jobs (id INTEGER NOT NULL PRIMARY KEY, employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME)' ActiveRecord::Base.connection.execute 'CREATE TABLE jobs (id INTEGER NOT NULL PRIMARY KEY, employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME)'
ActiveRecord::Base.connection.execute 'CREATE TABLE custom_column_models (id INTEGER NOT NULL PRIMARY KEY, destroyed_at DATETIME)' ActiveRecord::Base.connection.execute 'CREATE TABLE custom_column_models (id INTEGER NOT NULL PRIMARY KEY, destroyed_at DATETIME)'
ActiveRecord::Base.connection.execute 'CREATE TABLE non_paranoid_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER)'
class ParanoiaTest < Test::Unit::TestCase class ParanoiaTest < Test::Unit::TestCase
def test_plain_model_class_is_not_paranoid def test_plain_model_class_is_not_paranoid
...@@ -305,6 +306,34 @@ class ParanoiaTest < Test::Unit::TestCase ...@@ -305,6 +306,34 @@ class ParanoiaTest < Test::Unit::TestCase
refute c.destroyed? refute c.destroyed?
end end
def test_restore_with_associations
parent = ParentModel.create
first_child = parent.very_related_models.create
second_child = parent.non_paranoid_models.create
parent.destroy
assert_equal false, parent.deleted_at.nil?
assert_equal false, first_child.reload.deleted_at.nil?
assert_equal true, second_child.destroyed?
parent.restore!
assert_equal true, parent.deleted_at.nil?
assert_equal false, first_child.reload.deleted_at.nil?
assert_equal true, second_child.destroyed?
parent.destroy
parent.restore(:recursive => true)
assert_equal true, parent.deleted_at.nil?
assert_equal true, first_child.reload.deleted_at.nil?
assert_equal true, second_child.destroyed?
parent.destroy
ParentModel.restore(parent.id, :recursive => true)
assert_equal true, parent.reload.deleted_at.nil?
assert_equal true, first_child.reload.deleted_at.nil?
assert_equal true, second_child.destroyed?
end
def test_observers_notified def test_observers_notified
a = ParanoidModelWithObservers.create a = ParanoidModelWithObservers.create
a.destroy a.destroy
...@@ -366,6 +395,8 @@ end ...@@ -366,6 +395,8 @@ end
class ParentModel < ActiveRecord::Base class ParentModel < ActiveRecord::Base
acts_as_paranoid acts_as_paranoid
has_many :related_models has_many :related_models
has_many :very_related_models, :class_name => 'RelatedModel', dependent: :destroy
has_many :non_paranoid_models, dependent: :destroy
end end
class RelatedModel < ActiveRecord::Base class RelatedModel < ActiveRecord::Base
...@@ -395,6 +426,9 @@ class CustomColumnModel < ActiveRecord::Base ...@@ -395,6 +426,9 @@ class CustomColumnModel < ActiveRecord::Base
acts_as_paranoid column: :destroyed_at acts_as_paranoid column: :destroyed_at
end end
class NonParanoidModel < ActiveRecord::Base
end
class ParanoidModelWithObservers < ParanoidModel class ParanoidModelWithObservers < ParanoidModel
def observers_notified def observers_notified
@observers_notified ||= [] @observers_notified ||= []
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment