Skip to content

Commit 9c453c4

Browse files
authored
MONGOID-5110 Parent ID missing in after_destroy callback when removing via nested attribute (#5181)
* MONGOID-5110 Parent ID missing in after_destroy callback when removing via nested attribute * MONGOID-5110 remove byebug * MONGOID-5110 fix failing tests by using different models
1 parent 4cdc2e6 commit 9c453c4

File tree

6 files changed

+114
-13
lines changed

6 files changed

+114
-13
lines changed

lib/mongoid/association/embedded/embeds_many/proxy.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,20 +136,20 @@ def count(*args, &block)
136136
#
137137
# @return [ Document, nil ] The deleted document or nil if nothing deleted.
138138
def delete(document)
139-
execute_callback :before_remove, document
140-
doc = _target.delete_one(document)
141-
if doc && !_binding?
142-
_unscoped.delete_one(doc)
143-
if _assigning?
144-
_base.add_atomic_pull(doc)
145-
else
146-
doc.delete(suppress: true)
147-
unbind_one(doc)
139+
execute_callbacks_around(:remove, document) do
140+
doc = _target.delete_one(document)
141+
if doc && !_binding?
142+
_unscoped.delete_one(doc)
143+
if _assigning?
144+
_base.add_atomic_pull(doc)
145+
else
146+
doc.delete(suppress: true)
147+
unbind_one(doc)
148+
end
148149
end
150+
reindex
151+
doc
149152
end
150-
reindex
151-
execute_callback :after_remove, document
152-
doc
153153
end
154154

155155
# Delete all the documents in the association without running callbacks.

lib/mongoid/association/nested/many.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@ def destroy(parent, relation, doc)
134134
# @param [ Proxy ] relation The association proxy.
135135
# @param [ Document ] doc The document to delete.
136136
def destroy_document(relation, doc)
137+
res = doc.destroy unless doc.embedded? || doc.destroyed?
137138
relation.delete(doc)
138-
doc.destroy unless doc.embedded? || doc.destroyed?
139+
res
139140
end
140141

141142
# Update the document.

spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,24 @@ class HabtmmAnimal
6565

6666
has_and_belongs_to_many :trainers, inverse_of: :animals, class_name: 'HabtmmTrainer', scope: -> { where(name: 'Dave') }
6767
end
68+
69+
class HabtmmSchool
70+
include Mongoid::Document
71+
72+
has_and_belongs_to_many :students, class_name: 'HabtmmStudent'
73+
74+
field :after_destroy_triggered, default: false
75+
76+
accepts_nested_attributes_for :students, allow_destroy: true
77+
end
78+
79+
class HabtmmStudent
80+
include Mongoid::Document
81+
82+
has_and_belongs_to_many :schools, class_name: 'HabtmmSchool'
83+
84+
after_destroy do |doc|
85+
schools.first.update_attributes!(after_destroy_triggered: true) unless schools.empty?
86+
end
87+
end
88+

spec/mongoid/attributes/nested_spec.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22

33
require "spec_helper"
4+
require_relative '../association/referenced/has_many_models'
5+
require_relative '../association/referenced/has_and_belongs_to_many_models'
46

57
describe Mongoid::Attributes::Nested do
68

@@ -4921,4 +4923,53 @@ class BandWithAllowDestroyedRecords < Band
49214923
end
49224924
end
49234925
end
4926+
4927+
context "when destroying has_many child using nested attributes" do
4928+
let(:school) do
4929+
School.create
4930+
end
4931+
4932+
let!(:student) do
4933+
school.students.create
4934+
end
4935+
4936+
before do
4937+
school.attributes = {
4938+
'_id': school.id,
4939+
'students_attributes': [{
4940+
'_id': student.id,
4941+
'_destroy': 1
4942+
}]
4943+
}
4944+
end
4945+
4946+
it "is able to access the parent in the after_destroy callback" do
4947+
expect(school.after_destroy_triggered).to eq(true)
4948+
end
4949+
end
4950+
4951+
context "when destroying has_many child using nested attributes" do
4952+
let(:school) do
4953+
HabtmmSchool.create!(students: [student])
4954+
end
4955+
4956+
let(:student) do
4957+
HabtmmStudent.create!
4958+
end
4959+
4960+
before do
4961+
student.schools << school
4962+
school.attributes = {
4963+
'_id': school.id,
4964+
'students_attributes': [{
4965+
'_id': student.id,
4966+
'_destroy': 1
4967+
}]
4968+
}
4969+
end
4970+
4971+
it "is able to access the parent in the after_destroy callback" do
4972+
expect(school.reload.after_destroy_triggered).to eq(true)
4973+
end
4974+
end
49244975
end

spec/support/models/school.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
class School
4+
include Mongoid::Document
5+
6+
has_many :students
7+
8+
field :district, type: String
9+
field :team, type: String
10+
11+
field :after_destroy_triggered, default: false
12+
13+
accepts_nested_attributes_for :students, allow_destroy: true
14+
end

spec/support/models/student.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
class Student
4+
include Mongoid::Document
5+
6+
belongs_to :school
7+
8+
field :name, type: String
9+
field :grade, type: Integer, default: 3
10+
11+
after_destroy do |doc|
12+
school.after_destroy_triggered = true if school
13+
end
14+
end

0 commit comments

Comments
 (0)