mongoid 2.4.0 → 2.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +329 -1
- data/Rakefile +0 -9
- data/lib/config/locales/bg.yml +1 -0
- data/lib/config/locales/de.yml +1 -0
- data/lib/config/locales/en-GB.yml +1 -0
- data/lib/config/locales/en.yml +1 -0
- data/lib/config/locales/es.yml +1 -0
- data/lib/config/locales/fr.yml +1 -0
- data/lib/config/locales/hi.yml +1 -0
- data/lib/config/locales/hu.yml +1 -0
- data/lib/config/locales/id.yml +1 -0
- data/lib/config/locales/it.yml +1 -0
- data/lib/config/locales/ja.yml +1 -0
- data/lib/config/locales/kr.yml +1 -0
- data/lib/config/locales/nl.yml +1 -0
- data/lib/config/locales/pl.yml +1 -0
- data/lib/config/locales/pt-BR.yml +1 -0
- data/lib/config/locales/pt.yml +1 -0
- data/lib/config/locales/ro.yml +1 -0
- data/lib/config/locales/ru.yml +1 -0
- data/lib/config/locales/sv.yml +1 -0
- data/lib/config/locales/vi.yml +1 -0
- data/lib/config/locales/zh-CN.yml +1 -0
- data/lib/mongoid/atomic/modifiers.rb +56 -15
- data/lib/mongoid/atomic.rb +14 -8
- data/lib/mongoid/attributes.rb +1 -1
- data/lib/mongoid/callbacks.rb +3 -3
- data/lib/mongoid/collection.rb +5 -1
- data/lib/mongoid/collections/retry.rb +2 -1
- data/lib/mongoid/components.rb +2 -1
- data/lib/mongoid/config/database.rb +4 -7
- data/lib/mongoid/config/environment.rb +4 -2
- data/lib/mongoid/config/replset_database.rb +3 -5
- data/lib/mongoid/config.rb +18 -0
- data/lib/mongoid/contexts/enumerable.rb +26 -1
- data/lib/mongoid/contexts/mongo.rb +62 -14
- data/lib/mongoid/copyable.rb +38 -8
- data/lib/mongoid/criteria.rb +1 -0
- data/lib/mongoid/criterion/exclusion.rb +3 -1
- data/lib/mongoid/criterion/inclusion.rb +2 -2
- data/lib/mongoid/criterion/optional.rb +2 -2
- data/lib/mongoid/criterion/selector.rb +25 -4
- data/lib/mongoid/cursor.rb +4 -2
- data/lib/mongoid/dirty.rb +61 -18
- data/lib/mongoid/document.rb +6 -2
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +3 -1
- data/lib/mongoid/extensions/string/inflections.rb +1 -1
- data/lib/mongoid/factory.rb +3 -3
- data/lib/mongoid/fields/internal/array.rb +4 -9
- data/lib/mongoid/fields/internal/big_decimal.rb +7 -1
- data/lib/mongoid/fields/internal/date_time.rb +1 -1
- data/lib/mongoid/fields/internal/false_class.rb +10 -0
- data/lib/mongoid/fields/internal/foreign_keys/array.rb +22 -8
- data/lib/mongoid/fields/internal/set.rb +1 -1
- data/lib/mongoid/fields/internal/timekeeping.rb +2 -1
- data/lib/mongoid/fields/internal/true_class.rb +10 -0
- data/lib/mongoid/fields/mappings.rb +14 -13
- data/lib/mongoid/fields/serializable.rb +41 -3
- data/lib/mongoid/fields.rb +154 -26
- data/lib/mongoid/hierarchy.rb +6 -1
- data/lib/mongoid/identity_map.rb +15 -0
- data/lib/mongoid/logger.rb +7 -1
- data/lib/mongoid/matchers/all.rb +8 -1
- data/lib/mongoid/matchers/in.rb +8 -1
- data/lib/mongoid/matchers/strategies.rb +6 -2
- data/lib/mongoid/multi_database.rb +5 -0
- data/lib/mongoid/named_scope.rb +17 -1
- data/lib/mongoid/nested_attributes.rb +1 -1
- data/lib/mongoid/observer.rb +7 -0
- data/lib/mongoid/persistence/insertion.rb +2 -1
- data/lib/mongoid/persistence/operations/update.rb +0 -9
- data/lib/mongoid/persistence.rb +5 -5
- data/lib/mongoid/railtie.rb +22 -4
- data/lib/mongoid/relations/bindings/referenced/in.rb +31 -11
- data/lib/mongoid/relations/bindings/referenced/many.rb +8 -8
- data/lib/mongoid/relations/bindings/referenced/one.rb +8 -8
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +3 -1
- data/lib/mongoid/relations/cascading/delete.rb +29 -2
- data/lib/mongoid/relations/cascading/destroy.rb +18 -1
- data/lib/mongoid/relations/cascading/nullify.rb +18 -1
- data/lib/mongoid/relations/cascading.rb +0 -1
- data/lib/mongoid/relations/embedded/atomic.rb +3 -3
- data/lib/mongoid/relations/embedded/many.rb +58 -26
- data/lib/mongoid/relations/embedded/one.rb +1 -1
- data/lib/mongoid/relations/metadata.rb +33 -1
- data/lib/mongoid/relations/one.rb +12 -0
- data/lib/mongoid/relations/proxy.rb +6 -3
- data/lib/mongoid/relations/referenced/many.rb +14 -9
- data/lib/mongoid/relations/referenced/many_to_many.rb +3 -4
- data/lib/mongoid/relations/targets/enumerable.rb +9 -3
- data/lib/mongoid/relations.rb +3 -1
- data/lib/mongoid/serialization.rb +18 -6
- data/lib/mongoid/state.rb +1 -1
- data/lib/mongoid/threaded.rb +26 -0
- data/lib/mongoid/timestamps/updated.rb +1 -1
- data/lib/mongoid/validations/format.rb +20 -0
- data/lib/mongoid/validations/length.rb +20 -0
- data/lib/mongoid/validations/localizable.rb +30 -0
- data/lib/mongoid/validations/presence.rb +6 -2
- data/lib/mongoid/validations/uniqueness.rb +162 -30
- data/lib/mongoid/validations.rb +54 -2
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +12 -3
- data/lib/mongoid.rb +1 -0
- data/lib/rails/mongoid.rb +18 -12
- metadata +58 -41
- data/lib/mongoid/relations/cascading/strategy.rb +0 -26
data/lib/mongoid/named_scope.rb
CHANGED
|
@@ -56,7 +56,8 @@ module Mongoid #:nodoc:
|
|
|
56
56
|
(class << self; self; end).class_eval <<-EOT
|
|
57
57
|
def #{name}(*args)
|
|
58
58
|
scope = scopes[:#{name}]
|
|
59
|
-
scope.
|
|
59
|
+
conditions = scope.conditions.as_conditions(*args)
|
|
60
|
+
scope.extend(criteria.fuse(conditions))
|
|
60
61
|
end
|
|
61
62
|
EOT
|
|
62
63
|
end
|
|
@@ -123,6 +124,21 @@ module Mongoid #:nodoc:
|
|
|
123
124
|
end
|
|
124
125
|
end
|
|
125
126
|
|
|
127
|
+
# When inheriting, we want to copy the scopes from the parent class and
|
|
128
|
+
# set the on the child to start, mimicking the behaviour of the old
|
|
129
|
+
# class_inheritable_accessor that was deprecated in Rails edge.
|
|
130
|
+
#
|
|
131
|
+
# @example Inherit from this class.
|
|
132
|
+
# Person.inherited(Doctor)
|
|
133
|
+
#
|
|
134
|
+
# @param [ Class ] subclass The inheriting class.
|
|
135
|
+
#
|
|
136
|
+
# @since 2.0.0.rc.6
|
|
137
|
+
def inherited(subclass)
|
|
138
|
+
super
|
|
139
|
+
subclass.scopes = scopes.dup
|
|
140
|
+
end
|
|
141
|
+
|
|
126
142
|
protected
|
|
127
143
|
|
|
128
144
|
# Warns or raises exception if overriding another scope or method.
|
|
@@ -12,7 +12,7 @@ module Mongoid #:nodoc:
|
|
|
12
12
|
|
|
13
13
|
module ClassMethods #:nodoc:
|
|
14
14
|
|
|
15
|
-
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |
|
|
15
|
+
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }
|
|
16
16
|
|
|
17
17
|
# Used when needing to update related models from a parent relation. Can
|
|
18
18
|
# be used on embedded or referenced relations.
|
data/lib/mongoid/observer.rb
CHANGED
|
@@ -170,5 +170,12 @@ module Mongoid #:nodoc:
|
|
|
170
170
|
end
|
|
171
171
|
end
|
|
172
172
|
end
|
|
173
|
+
|
|
174
|
+
def disabled_for?(object)
|
|
175
|
+
klass = object.class
|
|
176
|
+
return false unless klass.respond_to?(:observers)
|
|
177
|
+
klass.observers.disabled_for?(self) || Mongoid.observers.disabled_for?(self)
|
|
178
|
+
end
|
|
179
|
+
|
|
173
180
|
end
|
|
174
181
|
end
|
|
@@ -25,11 +25,12 @@ module Mongoid #:nodoc:
|
|
|
25
25
|
doc.run_callbacks(:create) do
|
|
26
26
|
yield(doc)
|
|
27
27
|
doc.new_record = false
|
|
28
|
-
|
|
28
|
+
true
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
unless result == false
|
|
33
|
+
doc.reset_persisted_children
|
|
33
34
|
doc.move_changes
|
|
34
35
|
Threaded.clear_options!
|
|
35
36
|
end
|
|
@@ -42,15 +42,6 @@ module Mongoid #:nodoc:
|
|
|
42
42
|
def persist
|
|
43
43
|
prepare do
|
|
44
44
|
unless updates.empty?
|
|
45
|
-
# @todo Durran: This is a temporary fix for #791 until we rewrite
|
|
46
|
-
# the dirty tracking to properly flag a document as changed if
|
|
47
|
-
# only embedded documents have changed.
|
|
48
|
-
if document.respond_to?(:updated_at)
|
|
49
|
-
if document.timestamping? && !document.updated_at_changed?
|
|
50
|
-
document.updated_at = Time.now
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
45
|
collection.update(selector, updates, options)
|
|
55
46
|
conflicts.each_pair do |key, value|
|
|
56
47
|
collection.update(selector, { key => value }, options)
|
data/lib/mongoid/persistence.rb
CHANGED
|
@@ -116,8 +116,8 @@ module Mongoid #:nodoc:
|
|
|
116
116
|
# @param [ Hash ] attributes The attributes to update.
|
|
117
117
|
#
|
|
118
118
|
# @return [ true, false ] True if validation passed, false if not.
|
|
119
|
-
def update_attributes(attributes = {})
|
|
120
|
-
|
|
119
|
+
def update_attributes(attributes = {}, options = {})
|
|
120
|
+
assign_attributes(attributes, options); save
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
# Update the document attributes in the database and raise an error if
|
|
@@ -131,8 +131,8 @@ module Mongoid #:nodoc:
|
|
|
131
131
|
# @raise [ Errors::Validations ] If validation failed.
|
|
132
132
|
#
|
|
133
133
|
# @return [ true, false ] True if validation passed.
|
|
134
|
-
def update_attributes!(attributes = {})
|
|
135
|
-
update_attributes(attributes).tap do |result|
|
|
134
|
+
def update_attributes!(attributes = {}, options = {})
|
|
135
|
+
update_attributes(attributes, options).tap do |result|
|
|
136
136
|
unless result
|
|
137
137
|
self.class.fail_validate!(self) if errors.any?
|
|
138
138
|
self.class.fail_callback!(self, :update_attributes!)
|
|
@@ -151,7 +151,7 @@ module Mongoid #:nodoc:
|
|
|
151
151
|
# @return [ true, false ] True is success, false if not.
|
|
152
152
|
def upsert(options = {})
|
|
153
153
|
if new_record?
|
|
154
|
-
insert(options).
|
|
154
|
+
!insert(options).new_record?
|
|
155
155
|
else
|
|
156
156
|
update(options)
|
|
157
157
|
end
|
data/lib/mongoid/railtie.rb
CHANGED
|
@@ -23,8 +23,27 @@ module Rails #:nodoc:
|
|
|
23
23
|
config.respond_to?(:app_generators) ? :app_generators : :generators
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
# Maping of rescued exceptions to HTTP responses
|
|
27
|
+
#
|
|
28
|
+
# @example
|
|
29
|
+
# railtie.rescue_responses
|
|
30
|
+
#
|
|
31
|
+
# @ return [Hash] rescued responses
|
|
32
|
+
#
|
|
33
|
+
# @since 2.4.3
|
|
34
|
+
def self.rescue_responses
|
|
35
|
+
{
|
|
36
|
+
"Mongoid::Errors::DocumentNotFound" => :not_found,
|
|
37
|
+
"Mongoid::Errors::Validations" => 422
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
26
41
|
config.send(generator).orm :mongoid, :migration => false
|
|
27
42
|
|
|
43
|
+
if config.action_dispatch.rescue_responses
|
|
44
|
+
config.action_dispatch.rescue_responses.merge!(rescue_responses)
|
|
45
|
+
end
|
|
46
|
+
|
|
28
47
|
rake_tasks do
|
|
29
48
|
load "mongoid/railties/database.rake"
|
|
30
49
|
end
|
|
@@ -81,10 +100,9 @@ module Rails #:nodoc:
|
|
|
81
100
|
# 404s and not 500s, validation errors are 422s.
|
|
82
101
|
initializer "load http errors" do |app|
|
|
83
102
|
config.after_initialize do
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
})
|
|
103
|
+
unless config.action_dispatch.rescue_responses
|
|
104
|
+
ActionDispatch::ShowExceptions.rescue_responses.update(Railtie.rescue_responses)
|
|
105
|
+
end
|
|
88
106
|
end
|
|
89
107
|
end
|
|
90
108
|
|
|
@@ -19,17 +19,15 @@ module Mongoid # :nodoc:
|
|
|
19
19
|
#
|
|
20
20
|
# @since 2.0.0.rc.1
|
|
21
21
|
def bind
|
|
22
|
+
base.you_must(metadata.foreign_key_setter, target.id)
|
|
23
|
+
if metadata.inverse_type
|
|
24
|
+
base.you_must(metadata.inverse_type_setter, target.class.model_name)
|
|
25
|
+
end
|
|
22
26
|
unless _binding?
|
|
23
27
|
_binding do
|
|
24
28
|
inverse = metadata.inverse(target)
|
|
25
|
-
base.you_must(metadata.foreign_key_setter, target.id)
|
|
26
|
-
if metadata.inverse_type
|
|
27
|
-
base.you_must(metadata.inverse_type_setter, target.class.model_name)
|
|
28
|
-
end
|
|
29
29
|
if inverse
|
|
30
|
-
|
|
31
|
-
if inverse_metadata != metadata && !inverse_metadata.nil?
|
|
32
|
-
base.metadata = inverse_metadata
|
|
30
|
+
if set_base_metadata
|
|
33
31
|
if base.referenced_many?
|
|
34
32
|
target.send(inverse).push(base) unless Mongoid.identity_map_enabled?
|
|
35
33
|
else
|
|
@@ -51,14 +49,15 @@ module Mongoid # :nodoc:
|
|
|
51
49
|
#
|
|
52
50
|
# @since 2.0.0.rc.1
|
|
53
51
|
def unbind
|
|
52
|
+
base.you_must(metadata.foreign_key_setter, nil)
|
|
53
|
+
if metadata.inverse_type
|
|
54
|
+
base.you_must(metadata.inverse_type_setter, nil)
|
|
55
|
+
end
|
|
54
56
|
unless _binding?
|
|
55
57
|
_binding do
|
|
56
58
|
inverse = metadata.inverse(target)
|
|
57
|
-
base.you_must(metadata.foreign_key_setter, nil)
|
|
58
|
-
if metadata.inverse_type
|
|
59
|
-
base.you_must(metadata.inverse_type_setter, nil)
|
|
60
|
-
end
|
|
61
59
|
if inverse
|
|
60
|
+
set_base_metadata
|
|
62
61
|
if base.referenced_many?
|
|
63
62
|
target.send(inverse).delete(base)
|
|
64
63
|
else
|
|
@@ -69,6 +68,27 @@ module Mongoid # :nodoc:
|
|
|
69
68
|
end
|
|
70
69
|
end
|
|
71
70
|
alias :unbind_one :unbind
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# Ensure that the metadata on the base is correct, for the cases
|
|
75
|
+
# where we have multiple belongs to definitions and were are setting
|
|
76
|
+
# different parents in memory in order.
|
|
77
|
+
#
|
|
78
|
+
# @api private
|
|
79
|
+
#
|
|
80
|
+
# @example Set the base metadata.
|
|
81
|
+
# binding.set_base_metadata
|
|
82
|
+
#
|
|
83
|
+
# @return [ true, false ] If the metadata changed.
|
|
84
|
+
#
|
|
85
|
+
# @since 2.4.4
|
|
86
|
+
def set_base_metadata
|
|
87
|
+
inverse_metadata = metadata.inverse_metadata(target)
|
|
88
|
+
if inverse_metadata != metadata && !inverse_metadata.nil?
|
|
89
|
+
base.metadata = inverse_metadata
|
|
90
|
+
end
|
|
91
|
+
end
|
|
72
92
|
end
|
|
73
93
|
end
|
|
74
94
|
end
|
|
@@ -17,12 +17,12 @@ module Mongoid # :nodoc:
|
|
|
17
17
|
#
|
|
18
18
|
# @since 2.0.0.rc.1
|
|
19
19
|
def bind_one(doc)
|
|
20
|
+
doc.you_must(metadata.foreign_key_setter, base.id)
|
|
21
|
+
if metadata.type
|
|
22
|
+
doc.you_must(metadata.type_setter, base.class.model_name)
|
|
23
|
+
end
|
|
20
24
|
unless _binding?
|
|
21
25
|
_binding do
|
|
22
|
-
doc.you_must(metadata.foreign_key_setter, base.id)
|
|
23
|
-
if metadata.type
|
|
24
|
-
doc.you_must(metadata.type_setter, base.class.model_name)
|
|
25
|
-
end
|
|
26
26
|
doc.send(metadata.inverse_setter, base)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -37,12 +37,12 @@ module Mongoid # :nodoc:
|
|
|
37
37
|
#
|
|
38
38
|
# @since 2.0.0.rc.1
|
|
39
39
|
def unbind_one(doc)
|
|
40
|
+
doc.you_must(metadata.foreign_key_setter, nil)
|
|
41
|
+
if metadata.type
|
|
42
|
+
doc.you_must(metadata.type_setter, nil)
|
|
43
|
+
end
|
|
40
44
|
unless _binding?
|
|
41
45
|
_binding do
|
|
42
|
-
doc.you_must(metadata.foreign_key_setter, nil)
|
|
43
|
-
if metadata.type
|
|
44
|
-
doc.you_must(metadata.type_setter, nil)
|
|
45
|
-
end
|
|
46
46
|
doc.send(metadata.inverse_setter, nil)
|
|
47
47
|
end
|
|
48
48
|
end
|
|
@@ -19,13 +19,13 @@ module Mongoid # :nodoc:
|
|
|
19
19
|
#
|
|
20
20
|
# @since 2.0.0.rc.1
|
|
21
21
|
def bind
|
|
22
|
+
target.you_must(metadata.foreign_key_setter, base.id)
|
|
23
|
+
if metadata.type
|
|
24
|
+
target.you_must(metadata.type_setter, base.class.model_name)
|
|
25
|
+
end
|
|
22
26
|
unless _binding?
|
|
23
27
|
_binding do
|
|
24
|
-
target.you_must(metadata.foreign_key_setter, base.id)
|
|
25
28
|
target.send(metadata.inverse_setter, base)
|
|
26
|
-
if metadata.type
|
|
27
|
-
target.you_must(metadata.type_setter, base.class.model_name)
|
|
28
|
-
end
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
end
|
|
@@ -40,13 +40,13 @@ module Mongoid # :nodoc:
|
|
|
40
40
|
#
|
|
41
41
|
# @since 2.0.0.rc.1
|
|
42
42
|
def unbind
|
|
43
|
+
target.you_must(metadata.foreign_key_setter, nil)
|
|
44
|
+
if metadata.type
|
|
45
|
+
target.you_must(metadata.type_setter, nil)
|
|
46
|
+
end
|
|
43
47
|
unless _binding?
|
|
44
48
|
_binding do
|
|
45
|
-
target.you_must(metadata.foreign_key_setter, nil)
|
|
46
49
|
target.send(metadata.inverse_setter, nil)
|
|
47
|
-
if metadata.type
|
|
48
|
-
target.you_must(metadata.type_setter, nil)
|
|
49
|
-
end
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -92,7 +92,9 @@ module Mongoid # :nodoc:
|
|
|
92
92
|
def process(parent, attrs)
|
|
93
93
|
return if reject?(parent, attrs)
|
|
94
94
|
if id = attrs.extract_id
|
|
95
|
-
|
|
95
|
+
first = existing.first
|
|
96
|
+
converted = first ? convert_id(first.class, id) : id
|
|
97
|
+
doc = existing.find(converted)
|
|
96
98
|
if destroyable?(attrs)
|
|
97
99
|
existing.delete(doc)
|
|
98
100
|
doc.destroy unless doc.embedded?
|
|
@@ -2,7 +2,24 @@
|
|
|
2
2
|
module Mongoid # :nodoc:
|
|
3
3
|
module Relations #:nodoc:
|
|
4
4
|
module Cascading #:nodoc:
|
|
5
|
-
class Delete
|
|
5
|
+
class Delete
|
|
6
|
+
|
|
7
|
+
attr_accessor :document, :relation, :metadata
|
|
8
|
+
|
|
9
|
+
# Initialize the new cascade strategy, which will set up the relation
|
|
10
|
+
# and the metadata.
|
|
11
|
+
#
|
|
12
|
+
# @example Instantiate the strategy
|
|
13
|
+
# Strategy.new(document, metadata)
|
|
14
|
+
#
|
|
15
|
+
# @param [ Document ] document The document to cascade from.
|
|
16
|
+
# @param [ Metadata ] metadata The relation's metadata.
|
|
17
|
+
#
|
|
18
|
+
# @return [ Strategy ] The new strategy.
|
|
19
|
+
def initialize(document, metadata)
|
|
20
|
+
@document, @metadata = document, metadata
|
|
21
|
+
@relation = document.send(metadata.name)
|
|
22
|
+
end
|
|
6
23
|
|
|
7
24
|
# Execute the cascading deletion for the relation if it already exists.
|
|
8
25
|
# This should be optimized in the future potentially not to load all
|
|
@@ -10,8 +27,18 @@ module Mongoid # :nodoc:
|
|
|
10
27
|
#
|
|
11
28
|
# @example Perform the cascading delete.
|
|
12
29
|
# strategy.cascade
|
|
30
|
+
#
|
|
31
|
+
# @since 2.0.0
|
|
13
32
|
def cascade
|
|
14
|
-
|
|
33
|
+
if relation
|
|
34
|
+
if relation.cascades.empty?
|
|
35
|
+
safety = Threaded.safety_options
|
|
36
|
+
relation.clear
|
|
37
|
+
Threaded.safety_options = safety
|
|
38
|
+
else
|
|
39
|
+
::Array.wrap(relation).each { |doc| doc.delete }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
15
42
|
end
|
|
16
43
|
end
|
|
17
44
|
end
|
|
@@ -2,7 +2,24 @@
|
|
|
2
2
|
module Mongoid # :nodoc:
|
|
3
3
|
module Relations #:nodoc:
|
|
4
4
|
module Cascading #:nodoc:
|
|
5
|
-
class Destroy
|
|
5
|
+
class Destroy
|
|
6
|
+
|
|
7
|
+
attr_accessor :document, :relation, :metadata
|
|
8
|
+
|
|
9
|
+
# Initialize the new cascade strategy, which will set up the relation
|
|
10
|
+
# and the metadata.
|
|
11
|
+
#
|
|
12
|
+
# @example Instantiate the strategy
|
|
13
|
+
# Strategy.new(document, metadata)
|
|
14
|
+
#
|
|
15
|
+
# @param [ Document ] document The document to cascade from.
|
|
16
|
+
# @param [ Metadata ] metadata The relation's metadata.
|
|
17
|
+
#
|
|
18
|
+
# @return [ Strategy ] The new strategy.
|
|
19
|
+
def initialize(document, metadata)
|
|
20
|
+
@document, @metadata = document, metadata
|
|
21
|
+
@relation = document.send(metadata.name)
|
|
22
|
+
end
|
|
6
23
|
|
|
7
24
|
# Execute the cascading deletion for the relation if it already exists.
|
|
8
25
|
# This should be optimized in the future potentially not to load all
|
|
@@ -2,7 +2,24 @@
|
|
|
2
2
|
module Mongoid # :nodoc:
|
|
3
3
|
module Relations #:nodoc:
|
|
4
4
|
module Cascading #:nodoc:
|
|
5
|
-
class Nullify
|
|
5
|
+
class Nullify
|
|
6
|
+
|
|
7
|
+
attr_accessor :document, :relation, :metadata
|
|
8
|
+
|
|
9
|
+
# Initialize the new cascade strategy, which will set up the relation
|
|
10
|
+
# and the metadata.
|
|
11
|
+
#
|
|
12
|
+
# @example Instantiate the strategy
|
|
13
|
+
# Strategy.new(document, metadata)
|
|
14
|
+
#
|
|
15
|
+
# @param [ Document ] document The document to cascade from.
|
|
16
|
+
# @param [ Metadata ] metadata The relation's metadata.
|
|
17
|
+
#
|
|
18
|
+
# @return [ Strategy ] The new strategy.
|
|
19
|
+
def initialize(document, metadata)
|
|
20
|
+
@document, @metadata = document, metadata
|
|
21
|
+
@relation = document.send(metadata.name)
|
|
22
|
+
end
|
|
6
23
|
|
|
7
24
|
# This cascade does not delete the referenced relations, but instead
|
|
8
25
|
# sets the foreign key values to nil.
|
|
@@ -55,13 +55,13 @@ module Mongoid #:nodoc:
|
|
|
55
55
|
#
|
|
56
56
|
# @since 2.0.0
|
|
57
57
|
def atomically(modifier, &block)
|
|
58
|
-
updater = Threaded.update_consumer(
|
|
59
|
-
Threaded.set_update_consumer(
|
|
58
|
+
updater = Threaded.update_consumer(collection_name) ||
|
|
59
|
+
Threaded.set_update_consumer(collection_name, MODIFIERS[modifier].new)
|
|
60
60
|
count_executions do
|
|
61
61
|
block.call if block
|
|
62
62
|
end.tap do
|
|
63
63
|
if @executions.zero?
|
|
64
|
-
Threaded.set_update_consumer(
|
|
64
|
+
Threaded.set_update_consumer(collection_name, nil)
|
|
65
65
|
updater.execute(collection)
|
|
66
66
|
end
|
|
67
67
|
end
|
|
@@ -28,6 +28,22 @@ module Mongoid # :nodoc:
|
|
|
28
28
|
end
|
|
29
29
|
alias :push :<<
|
|
30
30
|
|
|
31
|
+
# Get this relation as as its representation in the database.
|
|
32
|
+
#
|
|
33
|
+
# @example Convert the relation to an attributes hash.
|
|
34
|
+
# person.addresses.as_document
|
|
35
|
+
#
|
|
36
|
+
# @return [ Array<Hash> ] The relation as stored in the db.
|
|
37
|
+
#
|
|
38
|
+
# @since 2.0.0.rc.1
|
|
39
|
+
def as_document
|
|
40
|
+
[].tap do |attributes|
|
|
41
|
+
_unscoped.each do |doc|
|
|
42
|
+
attributes.push(doc.as_document)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
31
47
|
# Appends an array of documents to the relation. Performs a batch
|
|
32
48
|
# insert of the documents instead of persisting one at a time.
|
|
33
49
|
#
|
|
@@ -78,6 +94,7 @@ module Mongoid # :nodoc:
|
|
|
78
94
|
Factory.build(type || metadata.klass, attributes, options).tap do |doc|
|
|
79
95
|
doc.identify
|
|
80
96
|
append(doc)
|
|
97
|
+
doc.apply_proc_defaults
|
|
81
98
|
yield(doc) if block_given?
|
|
82
99
|
doc.run_callbacks(:build) { doc }
|
|
83
100
|
end
|
|
@@ -172,12 +189,16 @@ module Mongoid # :nodoc:
|
|
|
172
189
|
target.delete_one(document).tap do |doc|
|
|
173
190
|
_unscoped.delete_one(doc)
|
|
174
191
|
if doc && !_binding?
|
|
175
|
-
if _assigning?
|
|
176
|
-
|
|
192
|
+
if _assigning?
|
|
193
|
+
if doc.paranoid?
|
|
194
|
+
doc.destroy(:suppress => true)
|
|
195
|
+
else
|
|
196
|
+
base.add_atomic_pull(doc)
|
|
197
|
+
end
|
|
177
198
|
else
|
|
178
199
|
doc.delete(:suppress => true)
|
|
200
|
+
unbind_one(doc)
|
|
179
201
|
end
|
|
180
|
-
unbind_one(doc)
|
|
181
202
|
end
|
|
182
203
|
reindex
|
|
183
204
|
end
|
|
@@ -283,46 +304,41 @@ module Mongoid # :nodoc:
|
|
|
283
304
|
tap do |proxy|
|
|
284
305
|
if replacement.blank?
|
|
285
306
|
if _assigning? && !proxy.empty?
|
|
286
|
-
base.atomic_unsets.push(
|
|
307
|
+
base.atomic_unsets.push(_unscoped.first.atomic_path)
|
|
287
308
|
end
|
|
288
309
|
proxy.clear
|
|
289
310
|
else
|
|
290
311
|
atomically(:$set) do
|
|
312
|
+
base.delayed_atomic_sets.clear unless _assigning?
|
|
291
313
|
if replacement.first.is_a?(Hash)
|
|
292
|
-
replacement =
|
|
314
|
+
replacement = replacement.map do |doc|
|
|
315
|
+
attributes = { :metadata => metadata, :_parent => base }
|
|
316
|
+
attributes.merge!(doc)
|
|
317
|
+
Factory.build(klass, attributes)
|
|
318
|
+
end
|
|
293
319
|
end
|
|
294
320
|
docs = replacement.compact
|
|
295
321
|
proxy.target = docs
|
|
296
322
|
self._unscoped = docs.dup
|
|
297
|
-
if _assigning?
|
|
298
|
-
base.delayed_atomic_sets[metadata.name.to_s] = proxy.as_document
|
|
299
|
-
end
|
|
300
323
|
proxy.target.each_with_index do |doc, index|
|
|
301
324
|
integrate(doc)
|
|
302
325
|
doc._index = index
|
|
303
326
|
doc.save if base.persisted? && !_assigning?
|
|
304
327
|
end
|
|
328
|
+
if _assigning?
|
|
329
|
+
name = _unscoped.first.atomic_path
|
|
330
|
+
base.delayed_atomic_sets[name].try(:clear)
|
|
331
|
+
base._children.each do |child|
|
|
332
|
+
child.delayed_atomic_sets.clear
|
|
333
|
+
end
|
|
334
|
+
base.instance_variable_set(:@_children, nil)
|
|
335
|
+
base.delayed_atomic_sets[name] = proxy.as_document
|
|
336
|
+
end
|
|
305
337
|
end
|
|
306
338
|
end
|
|
307
339
|
end
|
|
308
340
|
end
|
|
309
341
|
|
|
310
|
-
# Get this relation as as its representation in the database.
|
|
311
|
-
#
|
|
312
|
-
# @example Convert the relation to an attributes hash.
|
|
313
|
-
# person.addresses.as_document
|
|
314
|
-
#
|
|
315
|
-
# @return [ Array<Hash> ] The relation as stored in the db.
|
|
316
|
-
#
|
|
317
|
-
# @since 2.0.0.rc.1
|
|
318
|
-
def as_document
|
|
319
|
-
[].tap do |attributes|
|
|
320
|
-
_unscoped.each do |doc|
|
|
321
|
-
attributes.push(doc.as_document)
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
342
|
# Return the relation with all previous scoping removed. This is the
|
|
327
343
|
# exact representation of the docs in the database.
|
|
328
344
|
#
|
|
@@ -350,10 +366,10 @@ module Mongoid # :nodoc:
|
|
|
350
366
|
#
|
|
351
367
|
# @since 2.0.0.rc.1
|
|
352
368
|
def append(document)
|
|
353
|
-
target.push(document)
|
|
369
|
+
target.push(*scope([document]))
|
|
354
370
|
_unscoped.push(document)
|
|
355
371
|
integrate(document)
|
|
356
|
-
document._index =
|
|
372
|
+
document._index = _unscoped.size - 1
|
|
357
373
|
end
|
|
358
374
|
|
|
359
375
|
# Instantiate the binding associated with this relation.
|
|
@@ -383,6 +399,22 @@ module Mongoid # :nodoc:
|
|
|
383
399
|
end
|
|
384
400
|
end
|
|
385
401
|
|
|
402
|
+
# Deletes one document from the target and unscoped.
|
|
403
|
+
#
|
|
404
|
+
# @api private
|
|
405
|
+
#
|
|
406
|
+
# @example Delete one document.
|
|
407
|
+
# relation.delete_one(doc)
|
|
408
|
+
#
|
|
409
|
+
# @param [ Document ] document The document to delete.
|
|
410
|
+
#
|
|
411
|
+
# @since 2.4.7
|
|
412
|
+
def delete_one(document)
|
|
413
|
+
target.delete_one(document)
|
|
414
|
+
_unscoped.delete_one(document)
|
|
415
|
+
reindex
|
|
416
|
+
end
|
|
417
|
+
|
|
386
418
|
# Integrate the document into the relation. will set its metadata and
|
|
387
419
|
# attempt to bind the inverse.
|
|
388
420
|
#
|
|
@@ -717,6 +717,19 @@ module Mongoid # :nodoc:
|
|
|
717
717
|
!!self[:versioned]
|
|
718
718
|
end
|
|
719
719
|
|
|
720
|
+
# Returns the metadata itself. Here for compatibility with Rails
|
|
721
|
+
# association metadata.
|
|
722
|
+
#
|
|
723
|
+
# @example Get the options.
|
|
724
|
+
# metadata.options
|
|
725
|
+
#
|
|
726
|
+
# @return [ Metadata ] self.
|
|
727
|
+
#
|
|
728
|
+
# @since 2.4.6
|
|
729
|
+
def options
|
|
730
|
+
self
|
|
731
|
+
end
|
|
732
|
+
|
|
720
733
|
# Returns default order for this association.
|
|
721
734
|
#
|
|
722
735
|
# @example Get default order
|
|
@@ -848,7 +861,7 @@ module Mongoid # :nodoc:
|
|
|
848
861
|
#
|
|
849
862
|
# @since 2.0.0.rc.1
|
|
850
863
|
def determine_inverse_relation
|
|
851
|
-
default = klass.relations[inverse_klass.name.underscore]
|
|
864
|
+
default = foreign_key_match || klass.relations[inverse_klass.name.underscore]
|
|
852
865
|
return default.name if default
|
|
853
866
|
klass.relations.each_pair do |key, meta|
|
|
854
867
|
next if meta.versioned? || meta.name == name
|
|
@@ -859,6 +872,25 @@ module Mongoid # :nodoc:
|
|
|
859
872
|
return nil
|
|
860
873
|
end
|
|
861
874
|
|
|
875
|
+
# Return metadata where the foreign key matches the foreign key on this
|
|
876
|
+
# relation.
|
|
877
|
+
#
|
|
878
|
+
# @api private
|
|
879
|
+
#
|
|
880
|
+
# @example Return a foreign key match.
|
|
881
|
+
# meta.foreign_key_match
|
|
882
|
+
#
|
|
883
|
+
# @return [ Metadata ] A match, if any.
|
|
884
|
+
#
|
|
885
|
+
# @since 2.4.11
|
|
886
|
+
def foreign_key_match
|
|
887
|
+
if fk = self[:foreign_key]
|
|
888
|
+
klass.relations.values.detect do |meta|
|
|
889
|
+
fk == meta.foreign_key if meta.stores_foreign_key?
|
|
890
|
+
end
|
|
891
|
+
end
|
|
892
|
+
end
|
|
893
|
+
|
|
862
894
|
# Determine the key for the relation in the attributes.
|
|
863
895
|
#
|
|
864
896
|
# @example Get the key.
|
|
@@ -6,6 +6,18 @@ module Mongoid # :nodoc:
|
|
|
6
6
|
# behaviour or those proxies.
|
|
7
7
|
class One < Proxy
|
|
8
8
|
|
|
9
|
+
# Clear this relation - same as calling #delete on the document.
|
|
10
|
+
#
|
|
11
|
+
# @example Clear the relation.
|
|
12
|
+
# relation.clear
|
|
13
|
+
#
|
|
14
|
+
# @return [ true, false ] If the delete suceeded.
|
|
15
|
+
#
|
|
16
|
+
# @since 3.0.0
|
|
17
|
+
def clear
|
|
18
|
+
target.delete
|
|
19
|
+
end
|
|
20
|
+
|
|
9
21
|
# Get all the documents in the relation that are loaded into memory.
|
|
10
22
|
#
|
|
11
23
|
# @example Get the in memory documents.
|