Skip to content

MONGOID-5191 Proper order for after_create callback #5087

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Release Notes
.. toctree::
:titlesonly:

release-notes/mongoid-7.5
release-notes/mongoid-7.4
release-notes/mongoid-7.3
release-notes/mongoid-7.2
Expand Down
71 changes: 71 additions & 0 deletions docs/release-notes/mongoid-7.5.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
***********
Mongoid 7.5
***********

.. default-domain:: mongodb

.. contents:: On this page
:local:
:backlinks: none
:depth: 2
:class: singlecol

This page describes significant changes and improvements in Mongoid 7.5.
The complete list of releases is available `on GitHub
<https://github.com/mongodb/mongoid/releases>`_ and `in JIRA
<https://jira.mongodb.org/projects/MONGOID?selectedItem=com.atlassian.jira.jira-projects-plugin:release-page>`_;
please consult GitHub releases for detailed release notes and JIRA for
the complete list of issues fixed in each release, including bug fixes.


Order of Callbacks Invocation
-----------------------------

**Breaking change:** Mongoid 7.5 changes order of _create and _save callbacks
invocation for documents with associations.

Referenced associations (``has_one`` and ``has_many``):

+---------------------------------------+---------------------------------------+
| Mongoid 7.5 | Mongoid 7.4 |
+=======================================+=======================================+
| Parent :before_save | Parent :before_save |
+---------------------------------------+---------------------------------------+
| Parent :around_save_open | Parent :around_save_open |
+---------------------------------------+---------------------------------------+
| Parent :before_create | Parent :before_create |
+---------------------------------------+---------------------------------------+
| Parent :around_create_open | Parent :around_create_open |
+---------------------------------------+---------------------------------------+
| **Parent persisted in MongoDB** | **Parent persisted in MongoDB** |
+---------------------------------------+---------------------------------------+
| Child :before_save | Parent :around_create_close |
+---------------------------------------+---------------------------------------+
| Child :around_save_open | Parent :after_create |
+---------------------------------------+---------------------------------------+
| Child :before_create | Child :before_save |
+---------------------------------------+---------------------------------------+
| Child :around_create_open | Child :around_save_open |
+---------------------------------------+---------------------------------------+
| | Child :before_create |
+---------------------------------------+---------------------------------------+
| | Child :around_create_open |
+---------------------------------------+---------------------------------------+
| **Child persisted in MongoDB** | **Child persisted in MongoDB** |
+---------------------------------------+---------------------------------------+
| Child :around_create_close | Child :around_create_close |
+---------------------------------------+---------------------------------------+
| Child :after_create | Child :after_create |
+---------------------------------------+---------------------------------------+
| Child :around_save_close | Child :around_save_close |
+---------------------------------------+---------------------------------------+
| Child :after_save | Child :after_save |
+---------------------------------------+---------------------------------------+
| Parent :around_create_close | Parent :around_save_close |
+---------------------------------------+---------------------------------------+
| Parent :after_create | Parent :after_save |
+---------------------------------------+---------------------------------------+
| Parent :around_save_close | |
+---------------------------------------+---------------------------------------+
| Parent :after_save | |
+---------------------------------------+---------------------------------------+
4 changes: 2 additions & 2 deletions lib/mongoid/persistable/creatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ def prepare_insert(options = {})
return self if performing_validations?(options) &&
invalid?(options[:context] || :create)
result = run_callbacks(:save) do
run_callbacks(:persist_parent) do
run_callbacks(:create) do
run_callbacks(:create) do
run_callbacks(:persist_parent) do
yield(self)
post_process_insert
end
Expand Down
4 changes: 2 additions & 2 deletions lib/mongoid/persistable/updatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ def prepare_update(options = {})
invalid?(options[:context] || :update)
process_flagged_destroys
result = run_callbacks(:save) do
run_callbacks(:persist_parent) do
run_callbacks(:update) do
run_callbacks(:update) do
run_callbacks(:persist_parent) do
yield(self)
true
end
Expand Down
48 changes: 45 additions & 3 deletions spec/mongoid/interceptable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1798,7 +1798,7 @@ class TestClass

let(:parent) do
InterceptableSpec::CbHasOneParent.new(registry).tap do |p|
p.cb_has_one_child = InterceptableSpec::CbHasOneChild.new(registry)
p.child = InterceptableSpec::CbHasOneChild.new(registry)
end
end

Expand All @@ -1812,8 +1812,6 @@ class TestClass
[InterceptableSpec::CbHasOneParent, :around_save_open],
[InterceptableSpec::CbHasOneParent, :before_create],
[InterceptableSpec::CbHasOneParent, :around_create_open],
[InterceptableSpec::CbHasOneParent, :around_create_close],
[InterceptableSpec::CbHasOneParent, :after_create],
[InterceptableSpec::CbHasOneChild, :before_validation],
[InterceptableSpec::CbHasOneChild, :after_validation],
[InterceptableSpec::CbHasOneChild, :before_save],
Expand All @@ -1824,11 +1822,55 @@ class TestClass
[InterceptableSpec::CbHasOneChild, :after_create],
[InterceptableSpec::CbHasOneChild, :around_save_close],
[InterceptableSpec::CbHasOneChild, :after_save],
[InterceptableSpec::CbHasOneParent, :around_create_close],
[InterceptableSpec::CbHasOneParent, :after_create],
[InterceptableSpec::CbHasOneParent, :around_save_close],
[InterceptableSpec::CbHasOneParent, :after_save],
]
end

it 'calls callbacks in the right order' do
parent.save!
expect(registry.calls).to eq expected
end
end

context "has_many" do
let(:registry) { InterceptableSpec::CallbackRegistry.new }

let(:parent) do
InterceptableSpec::CbHasManyParent.new(registry).tap do |p|
p.children = [InterceptableSpec::CbHasManyChild.new(registry)]
end
end

let(:expected) do
[
[InterceptableSpec::CbHasManyParent, :before_validation],
[InterceptableSpec::CbHasManyChild, :before_validation],
[InterceptableSpec::CbHasManyChild, :after_validation],
[InterceptableSpec::CbHasManyParent, :after_validation],
[InterceptableSpec::CbHasManyParent, :before_save],
[InterceptableSpec::CbHasManyParent, :around_save_open],
[InterceptableSpec::CbHasManyParent, :before_create],
[InterceptableSpec::CbHasManyParent, :around_create_open],
[InterceptableSpec::CbHasManyChild, :before_validation],
[InterceptableSpec::CbHasManyChild, :after_validation],
[InterceptableSpec::CbHasManyChild, :before_save],
[InterceptableSpec::CbHasManyChild, :around_save_open],
[InterceptableSpec::CbHasManyChild, :before_create],
[InterceptableSpec::CbHasManyChild, :around_create_open],
[InterceptableSpec::CbHasManyChild, :around_create_close],
[InterceptableSpec::CbHasManyChild, :after_create],
[InterceptableSpec::CbHasManyChild, :around_save_close],
[InterceptableSpec::CbHasManyChild, :after_save],
[InterceptableSpec::CbHasManyParent, :around_create_close],
[InterceptableSpec::CbHasManyParent, :after_create],
[InterceptableSpec::CbHasManyParent, :around_save_close],
[InterceptableSpec::CbHasManyParent, :after_save],
]
end

it 'calls callbacks in the right order' do

parent.save!
Expand Down
34 changes: 32 additions & 2 deletions spec/mongoid/interceptable_spec_models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module CallbackTracking
class CbHasOneParent
include Mongoid::Document

has_one :cb_has_one_child, autosave: true, class_name: "CbHasOneChild", inverse_of: :cb_has_one_parent
has_one :child, autosave: true, class_name: "CbHasOneChild", inverse_of: :parent

def initialize(callback_registry)
@callback_registry = callback_registry
Expand All @@ -54,7 +54,37 @@ def initialize(callback_registry)
class CbHasOneChild
include Mongoid::Document

belongs_to :cb_has_one_parent, class_name: "CbHasOneParent", inverse_of: :cb_has_one_child
belongs_to :parent, class_name: "CbHasOneParent", inverse_of: :child

def initialize(callback_registry)
@callback_registry = callback_registry
super()
end

attr_reader :callback_registry

include CallbackTracking
end

class CbHasManyParent
include Mongoid::Document

has_many :children, autosave: true, class_name: "CbHasManyChild", inverse_of: :parent

def initialize(callback_registry)
@callback_registry = callback_registry
super()
end

attr_reader :callback_registry

include CallbackTracking
end

class CbHasManyChild
include Mongoid::Document

belongs_to :parent, class_name: "CbHasManyParent", inverse_of: :children

def initialize(callback_registry)
@callback_registry = callback_registry
Expand Down