diff --git a/lib/mongoid/paranoia.rb b/lib/mongoid/paranoia.rb index f764735..efeb61f 100644 --- a/lib/mongoid/paranoia.rb +++ b/lib/mongoid/paranoia.rb @@ -138,7 +138,12 @@ def to_param def restore_relations self.relations.each_pair do |name, metadata| next unless metadata[:dependent] == :destroy - relation = self.send(name) + relation_model = metadata[:class_name].try(:safe_constantize) || name.classify.safe_constantize + if relation_model + relation = relation_model.unscoped { self.send(name) } + else + next + end if relation.present? && relation.paranoid? Array.wrap(relation).each do |doc| doc.restore(:recursive => true) diff --git a/lib/mongoid/paranoia/monkey_patches.rb b/lib/mongoid/paranoia/monkey_patches.rb index a03f94a..605307a 100644 --- a/lib/mongoid/paranoia/monkey_patches.rb +++ b/lib/mongoid/paranoia/monkey_patches.rb @@ -111,3 +111,26 @@ def deleted end end end + +module Mongoid + module Relations + module Synchronization + # Update the inverse keys on destroy. + # + # @example Update the inverse keys. + # document.remove_inverse_keys(metadata) + # + # @param [ Metadata ] meta The document metadata. + # + # @return [ Object ] The updated values. + # + # @since 2.2.1 + def remove_inverse_keys(meta) + foreign_keys = send(meta.foreign_key) + unless foreign_keys.nil? || foreign_keys.empty? || self.paranoid? + meta.criteria(foreign_keys, self.class).pull(meta.inverse_foreign_key => _id) + end + end + end + end +end diff --git a/spec/mongoid/paranoia_spec.rb b/spec/mongoid/paranoia_spec.rb index 814b6f5..b17bd2a 100644 --- a/spec/mongoid/paranoia_spec.rb +++ b/spec/mongoid/paranoia_spec.rb @@ -688,25 +688,26 @@ describe "#restore_relations" do - subject { ParaBase.create } - - let!(:para_has_one) { subject.para_has_one = ParaHasOne.create } - let!(:para_has_many) { 2.times.map { subject.para_has_many.create } } - let!(:para_habtm) { 3.times.map { subject.para_habtm.create } } - let!(:para_belongs_to) { subject.para_belongs_to = ParaBelongsTo.create } - let!(:para_embeds_one) { subject.para_embeds_one = ParaEmbedsOne.new } - let!(:para_embeds_many) { 2.times.map { subject.para_embeds_many.build } } - - let!(:norm_has_one) { subject.norm_has_one = NormHasOne.create } - let!(:norm_has_many) { 2.times.map { subject.norm_has_many.create } } - let!(:norm_habtm) { 3.times.map { subject.norm_habtm.create } } - let!(:norm_belongs_to) { subject.norm_belongs_to = NormBelongsTo.create } - let!(:norm_embeds_one) { subject.norm_embeds_one = NormEmbedsOne.new } - let!(:norm_embeds_many) { 2.times.map { subject.norm_embeds_many.build } } + subject { ParaBase.find(para_base.id) } + + let(:para_base) { ParaBase.create } + let!(:para_has_one) { para_base.update(para_has_one: ParaHasOne.create) } + let!(:para_has_many) { 2.times.map { para_base.para_has_many.create } } + let!(:para_habtm) { 3.times.map { para_base.para_habtm.create } } + let!(:para_belongs_to) { para_base.update(para_belongs_to: ParaBelongsTo.create) } + let!(:para_embeds_one) { para_base.update(para_embeds_one: ParaEmbedsOne.new) } + let!(:para_embeds_many) { 2.times.map { para_base.para_embeds_many.create } } + + let!(:norm_has_one) { para_base.update(norm_has_one: NormHasOne.create) } + let!(:norm_has_many) { 2.times.map { para_base.norm_has_many.create } } + let!(:norm_habtm) { 3.times.map { para_base.norm_habtm.create } } + let!(:norm_belongs_to) { para_base.update(norm_belongs_to: NormBelongsTo.create) } + let!(:norm_embeds_one) { para_base.update(norm_embeds_one: NormEmbedsOne.new) } + let!(:norm_embeds_many) { 2.times.map { para_base.norm_embeds_many.build } } let(:prepare) do - subject.destroy - subject.restore + para_base.destroy + para_base.restore end context "restores paranoid associations" do @@ -738,18 +739,18 @@ context "recursion" do - let!(:para_habtm_norm_has_one) { subject.para_habtm.first.norm_has_one = NormHasOne.create } # not restored - let!(:para_habtm_para_has_one) { subject.para_habtm.first.para_has_one = ParaHasOne.create } # restored - let!(:para_habtm_norm_has_many) { 2.times.map { subject.para_habtm.first.norm_has_many = NormHasMany.create } } # not restored - let!(:para_habtm_para_has_many) { 3.times.map { subject.para_habtm.second.para_has_many = ParaHasMany.create } } # restored + let!(:para_habtm_norm_has_one) { para_base.para_habtm.first.update(norm_has_one: NormHasOne.create) } # not restored + let!(:para_habtm_para_has_one) { para_base.para_habtm.first.update(para_has_one: ParaHasOne.create) } # restored + let!(:para_habtm_norm_has_many) { 2.times.map { para_base.para_habtm.first.update(norm_has_many: NormHasMany.create) } } # not restored + let!(:para_habtm_para_has_many) { 3.times.map { para_base.para_habtm.second.update(para_has_many: ParaHasMany.create) } } # restored # Untestable due to infinite recursion condition in #destroy # let!(:para_habtm_norm_habtm) { 3.times.map { subject.para_habtm.second.norm_habtm.create } } # not restored # let!(:para_habtm_recursive) { 2.times.map { subject.para_habtm.first.recursive.create } } # restored before do - subject.destroy - subject.restore + para_base.destroy + para_base.restore end it { expect{ subject.restore_relations}.to change { ParaHasOne.count }.by(2) }