Module: Mongoid::Interceptable

Extended by:
ActiveSupport::Concern
Included in:
Composable
Defined in:
lib/mongoid/interceptable.rb

Overview

This module contains all the callback hooks for Mongoid.

Constant Summary collapse

CALLBACKS =
[
  :after_build,
  :after_create,
  :after_destroy,
  :after_find,
  :after_initialize,
  :after_save,
  :after_touch,
  :after_update,
  :after_upsert,
  :after_validation,
  :around_create,
  :around_destroy,
  :around_save,
  :around_update,
  :around_upsert,
  :before_create,
  :before_destroy,
  :before_save,
  :before_update,
  :before_upsert,
  :before_validation,
].freeze

Instance Method Summary collapse

Instance Method Details

#_mongoid_run_child_callbacks(kind, children: nil, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Run the callbacks for embedded documents.

Parameters:

  • kind (Symbol)

    The type of callback to execute.

  • children (Array<Document>) (defaults to: nil)

    Children to execute callbacks on. If nil, callbacks will be executed on all cascadable children of the document.



150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/mongoid/interceptable.rb', line 150

def _mongoid_run_child_callbacks(kind, children: nil, &block)
  child, *tail = (children || cascadable_children(kind))
  if child.nil?
    return block&.call
  elsif tail.empty?
    return child.run_callbacks(child_callback_type(kind, child), &block)
  else
    return child.run_callbacks(child_callback_type(kind, child)) do
      _mongoid_run_child_callbacks(kind, children: tail, &block)
    end
  end
end

#callback_executable?(kind) ⇒ true | false

Is the provided type of callback executable by this document?

Examples:

Is the callback executable?

document.callback_executable?(:save)

Parameters:

  • kind (Symbol)

    The type of callback.

Returns:

  • (true | false)

    If the callback can be executed.



59
60
61
# File 'lib/mongoid/interceptable.rb', line 59

def callback_executable?(kind)
  respond_to?("_#{kind}_callbacks")
end

#in_callback_state?(kind) ⇒ true | false

Is the document currently in a state that could potentially require callbacks to be executed?

Examples:

Is the document in a callback state?

document.in_callback_state?(:update)

Parameters:

  • kind (Symbol)

    The callback kind.

Returns:

  • (true | false)

    If the document is in a callback state.



72
73
74
# File 'lib/mongoid/interceptable.rb', line 72

def in_callback_state?(kind)
  [ :create, :destroy ].include?(kind) || new_record? || flagged_for_destroy? || changed?
end

#pending_callbacksArray<Symbol>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This is used to store callbacks to be executed later. A good use case for this is delaying the after_find and after_initialize callbacks until the associations are set on the document. This can also be used to delay applying the defaults on a document.

Returns:

  • (Array<Symbol>)

    an array of symbols that represent the pending callbacks.



171
172
173
# File 'lib/mongoid/interceptable.rb', line 171

def pending_callbacks
  @pending_callbacks ||= [].to_set
end

#pending_callbacks=(value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



176
177
178
# File 'lib/mongoid/interceptable.rb', line 176

def pending_callbacks=(value)
  @pending_callbacks = value
end

#run_after_callbacks(*kinds) ⇒ Object

Note:

ActiveSupport does not allow this type of behavior by default, so Mongoid has to get around it and implement itself.

Run only the after callbacks for the specific event.

Examples:

Run only the after save callbacks.

model.run_after_callbacks(:save)

Parameters:

  • *kinds (Symbol...)

    The events that are occurring.

Returns:

  • (Object)

    The result of the chain executing.



87
88
89
90
91
# File 'lib/mongoid/interceptable.rb', line 87

def run_after_callbacks(*kinds)
  kinds.each do |kind|
    run_targeted_callbacks(:after, kind)
  end
end

#run_before_callbacks(*kinds) ⇒ Object

Note:

ActiveSupport does not allow this type of behavior by default, so Mongoid has to get around it and implement itself.

Run only the before callbacks for the specific event.

Examples:

Run only the before save callbacks.

model.run_before_callbacks(:save, :create)

Parameters:

  • *kinds (Symbol...)

    The events that are occurring.

Returns:

  • (Object)

    The result of the chain executing.



104
105
106
107
108
# File 'lib/mongoid/interceptable.rb', line 104

def run_before_callbacks(*kinds)
  kinds.each do |kind|
    run_targeted_callbacks(:before, kind)
  end
end

#run_callbacks(kind, with_children: true, skip_if: nil, &block) ⇒ Object

Run the callbacks for the document. This overrides active support’s functionality to cascade callbacks to embedded documents that have been flagged as such.

Examples:

Run the callbacks.

run_callbacks :save do
  save!
end

Parameters:

  • kind (Symbol)

    The type of callback to execute.

  • with_children (true | false) (defaults to: true)

    Flag specifies whether callbacks of embedded document should be run.

  • skip_if (Proc | nil) (defaults to: nil)

    If this proc returns true, the callbacks will not be triggered, while the given block will be still called.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/mongoid/interceptable.rb', line 124

def run_callbacks(kind, with_children: true, skip_if: nil, &block)
  if skip_if&.call
    return block&.call
  end
  if with_children
    cascadable_children(kind).each do |child|
      if child.run_callbacks(child_callback_type(kind, child), with_children: with_children) == false
        return false
      end
    end
  end
  if callback_executable?(kind)
    super(kind, &block)
  else
    true
  end
end

#run_pending_callbacksObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Run the pending callbacks. If the callback is :apply_defaults, we will apply the defaults for this document. Otherwise, the callback is passed to the run_callbacks function.



185
186
187
188
189
190
191
192
193
194
# File 'lib/mongoid/interceptable.rb', line 185

def run_pending_callbacks
  pending_callbacks.each do |cb|
    if [:apply_defaults, :apply_post_processed_defaults].include?(cb)
      send(cb)
    else
      self.run_callbacks(cb, with_children: false)
    end
  end
  pending_callbacks.clear
end