Skip to content

Commit

Permalink
MONGOID-3795 Clarify/improve order of callback invocation on embedded…
Browse files Browse the repository at this point in the history
… associations vs host documents
  • Loading branch information
p committed Dec 7, 2018
1 parent 92e1725 commit 9944c03
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 2 deletions.
5 changes: 3 additions & 2 deletions docs/tutorials/mongoid-relations.txt
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ associations with the exception of ``has_and_belongs_to_many``.
Cascading Callbacks
*******************

If you want the embedded document callbacks to fire when calling a persistence operation on
its parent, you will need to provide the cascade callbacks option to the association.
If you want the embedded document callbacks to fire when calling a persistence
operation on its parent, you will need to provide the cascade callbacks option
to the association.

.. code-block:: ruby

Expand Down
60 changes: 60 additions & 0 deletions spec/mongoid/interceptable_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require "spec_helper"
require_relative './interceptable_spec_models'

describe Mongoid::Interceptable do

Expand Down Expand Up @@ -1721,4 +1722,63 @@ class TestClass
end
end
end

context 'when creating a parent and embedded child' do
let(:registry) { InterceptableSpec::CallbackRegistry.new }
let(:parent) do
InterceptableSpec::CbParent.new(registry).tap do |parent|
parent.cb_children << InterceptableSpec::CbChild.new(registry, cb_parent: parent)
end
end

let(:expected) do
[
[InterceptableSpec::CbParent, :before_validation],
[InterceptableSpec::CbChild, :before_validation],
[InterceptableSpec::CbChild, :after_validation],
[InterceptableSpec::CbParent, :after_validation],
[InterceptableSpec::CbParent, :before_save],
[InterceptableSpec::CbParent, :before_create],
[InterceptableSpec::CbParent, :after_create],
[InterceptableSpec::CbParent, :after_save],
]
end

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

context 'when creating a parent and embedded child with cascading callbacks' do
let(:registry) { InterceptableSpec::CallbackRegistry.new }
let(:parent) do
InterceptableSpec::CbParent.new(registry).tap do |parent|
parent.cb_cascaded_children <<
InterceptableSpec::CbCascadedChild.new(registry, cb_parent: parent)
end
end

let(:expected) do
[
[InterceptableSpec::CbParent, :before_validation],
[InterceptableSpec::CbCascadedChild, :before_validation],
[InterceptableSpec::CbCascadedChild, :after_validation],
[InterceptableSpec::CbParent, :after_validation],
[InterceptableSpec::CbParent, :before_save],
[InterceptableSpec::CbCascadedChild, :before_save],
[InterceptableSpec::CbParent, :before_create],
[InterceptableSpec::CbCascadedChild, :before_create],
[InterceptableSpec::CbParent, :after_create],
[InterceptableSpec::CbCascadedChild, :after_create],
[InterceptableSpec::CbParent, :after_save],
[InterceptableSpec::CbCascadedChild, :after_save],
]
end

it 'calls callbacks in the right order' do
parent.save!
expect(registry.calls).to eq expected
end
end
end
76 changes: 76 additions & 0 deletions spec/mongoid/interceptable_spec_models.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
module InterceptableSpec
class CallbackRegistry
def initialize
@calls = []
end

def record_call(cls, cb)
@calls << [cls, cb]
end

attr_reader :calls
end

module CallbackTracking
extend ActiveSupport::Concern

included do
%i(
validation save create update
).each do |what|
%i(before after).each do |whn|
send("#{whn}_#{what}", "#{whn}_#{what}_stub".to_sym)
define_method("#{whn}_#{what}_stub") do
callback_registry.record_call(self.class, "#{whn}_#{what}".to_sym)
end
end
end
end
end

class CbParent
include Mongoid::Document

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

attr_reader :callback_registry

embeds_many :cb_children
embeds_many :cb_cascaded_children, cascade_callbacks: true

include CallbackTracking
end

class CbChild
include Mongoid::Document

embedded_in :cb_parent

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

attr_reader :callback_registry

include CallbackTracking
end

class CbCascadedChild
include Mongoid::Document

embedded_in :cb_parent

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

attr_reader :callback_registry

include CallbackTracking
end
end

0 comments on commit 9944c03

Please sign in to comment.