|
1 | | -# Backport Mongoid 4 :touch option for #embedded_in to Mongoid 3. |
| 1 | +# Backport support #embedded_in :touch option from Mongoid 4 to Mongoid 3. |
| 2 | +# Also support touch callback on update, and fix infinite loop issue. |
2 | 3 |
|
3 | 4 | if Mongoid::VERSION =~ /\A3\./ |
4 | 5 |
|
5 | 6 | module Mongoid |
6 | | -module Relations |
7 | | - module Embedded |
8 | | - class In < Relations::One |
9 | | - class << self |
10 | | - def valid_options |
11 | | - [ :autobuild, :cyclic, :polymorphic, :touch ] |
| 7 | + module Relations |
| 8 | + module Embedded |
| 9 | + class In < Relations::One |
| 10 | + class << self |
| 11 | + def valid_options |
| 12 | + [ :autobuild, :cyclic, :polymorphic, :touch ] |
| 13 | + end |
| 14 | + end |
| 15 | + end |
| 16 | + end |
| 17 | + |
| 18 | + module Macros |
| 19 | + module ClassMethods |
| 20 | + |
| 21 | + def embedded_in(name, options = {}, &block) |
| 22 | + if ancestors.include?(Mongoid::Versioning) |
| 23 | + raise Errors::VersioningNotOnRoot.new(self) |
| 24 | + end |
| 25 | + meta = characterize(name, Embedded::In, options, &block) |
| 26 | + self.embedded = true |
| 27 | + relate(name, meta) |
| 28 | + builder(name, meta).creator(name, meta) |
| 29 | + touchable(meta) |
| 30 | + add_counter_cache_callbacks(meta) if meta.counter_cached? |
| 31 | + meta |
12 | 32 | end |
13 | 33 | end |
14 | 34 | end |
15 | | - end |
16 | 35 |
|
17 | | - module Macros |
18 | | - module ClassMethods |
| 36 | + module Touchable |
| 37 | + module ClassMethods |
19 | 38 |
|
20 | | - def embedded_in(name, options = {}, &block) |
21 | | - if ancestors.include?(Mongoid::Versioning) |
22 | | - raise Errors::VersioningNotOnRoot.new(self) |
| 39 | + def touchable(metadata) |
| 40 | + if metadata.touchable? |
| 41 | + name = metadata.name |
| 42 | + method_name = define_relation_touch_method(name) |
| 43 | + after_save method_name |
| 44 | + after_destroy method_name |
| 45 | + after_touch method_name |
| 46 | + end |
| 47 | + self |
23 | 48 | end |
24 | | - meta = characterize(name, Embedded::In, options, &block) |
25 | | - self.embedded = true |
26 | | - relate(name, meta) |
27 | | - builder(name, meta).creator(name, meta) |
28 | | - touchable(meta) |
29 | | - add_counter_cache_callbacks(meta) if meta.counter_cached? |
30 | | - meta |
31 | 49 | end |
32 | 50 | end |
33 | 51 | end |
| 52 | + |
| 53 | + module Callbacks |
| 54 | + def cascadable_children(kind, children = Set.new) |
| 55 | + embedded_relations.each_pair do |name, metadata| |
| 56 | + next unless metadata.cascading_callbacks? |
| 57 | + without_autobuild do |
| 58 | + delayed_pulls = delayed_atomic_pulls[name] |
| 59 | + delayed_unsets = delayed_atomic_unsets[name] |
| 60 | + children.merge(delayed_pulls) if delayed_pulls |
| 61 | + children.merge(delayed_unsets) if delayed_unsets |
| 62 | + relation = send(name) |
| 63 | + Array.wrap(relation).each do |child| |
| 64 | + next if children.include?(child) |
| 65 | + children.add(child) if cascadable_child?(kind, child, metadata) |
| 66 | + child.send(:cascadable_children, kind, children) |
| 67 | + end |
| 68 | + end |
| 69 | + end |
| 70 | + children.to_a |
| 71 | + end |
| 72 | + |
| 73 | + def cascadable_child?(kind, child, metadata) |
| 74 | + return false if kind == :initialize || kind == :find || kind == :touch |
| 75 | + return false if kind == :validate && metadata.validate? |
| 76 | + child.callback_executable?(kind) ? child.in_callback_state?(kind) : false |
| 77 | + end |
| 78 | + end |
34 | 79 | end |
| 80 | + |
| 81 | +end |
| 82 | + |
| 83 | +if Mongoid::VERSION =~ /\A[45]\./ |
| 84 | + |
| 85 | +module Mongoid |
| 86 | + |
| 87 | + module Interceptable |
| 88 | + def cascadable_child?(kind, child, metadata) |
| 89 | + return false if kind == :initialize || kind == :find || kind == :touch |
| 90 | + return false if kind == :validate && metadata.validate? |
| 91 | + child.callback_executable?(kind) ? child.in_callback_state?(kind) : false |
| 92 | + end |
| 93 | + end |
35 | 94 | end |
36 | 95 |
|
37 | 96 | end |
0 commit comments