mongoid 2.2.6 → 2.3.0
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 +2 -858
- data/Rakefile +2 -5
- data/lib/mongoid.rb +1 -1
- data/lib/mongoid/attributes.rb +68 -18
- data/lib/mongoid/attributes/processing.rb +4 -3
- data/lib/mongoid/callbacks.rb +102 -0
- data/lib/mongoid/collection.rb +1 -1
- data/lib/mongoid/components.rb +2 -1
- data/lib/mongoid/contexts/enumerable.rb +0 -24
- data/lib/mongoid/contexts/mongo.rb +2 -2
- data/lib/mongoid/copyable.rb +3 -1
- data/lib/mongoid/criteria.rb +18 -10
- data/lib/mongoid/criterion/complex.rb +11 -0
- data/lib/mongoid/criterion/inclusion.rb +38 -7
- data/lib/mongoid/criterion/optional.rb +2 -7
- data/lib/mongoid/criterion/selector.rb +1 -0
- data/lib/mongoid/dirty.rb +19 -0
- data/lib/mongoid/document.rb +16 -12
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +1 -1
- data/lib/mongoid/extensions/object/checks.rb +4 -1
- data/lib/mongoid/extensions/object_id/conversions.rb +4 -2
- data/lib/mongoid/extensions/string/inflections.rb +2 -2
- data/lib/mongoid/factory.rb +7 -2
- data/lib/mongoid/fields.rb +4 -10
- data/lib/mongoid/fields/serializable.rb +18 -2
- data/lib/mongoid/fields/serializable/integer.rb +17 -5
- data/lib/mongoid/fields/serializable/localized.rb +41 -0
- data/lib/mongoid/finders.rb +5 -4
- data/lib/mongoid/hierarchy.rb +87 -84
- data/lib/mongoid/identity.rb +4 -2
- data/lib/mongoid/keys.rb +2 -1
- data/lib/mongoid/logger.rb +1 -7
- data/lib/mongoid/matchers/and.rb +30 -0
- data/lib/mongoid/matchers/in.rb +1 -1
- data/lib/mongoid/matchers/nin.rb +1 -1
- data/lib/mongoid/matchers/strategies.rb +6 -4
- data/lib/mongoid/multi_parameter_attributes.rb +3 -2
- data/lib/mongoid/named_scope.rb +3 -13
- data/lib/mongoid/nested_attributes.rb +1 -1
- data/lib/mongoid/paranoia.rb +2 -3
- data/lib/mongoid/persistence.rb +9 -5
- data/lib/mongoid/persistence/atomic/operation.rb +1 -1
- data/lib/mongoid/persistence/deletion.rb +1 -1
- data/lib/mongoid/persistence/insertion.rb +1 -1
- data/lib/mongoid/persistence/modification.rb +1 -1
- data/lib/mongoid/railtie.rb +1 -1
- data/lib/mongoid/railties/database.rake +9 -1
- data/lib/mongoid/relations.rb +1 -0
- data/lib/mongoid/relations/accessors.rb +1 -1
- data/lib/mongoid/relations/builders.rb +6 -4
- data/lib/mongoid/relations/builders/referenced/many.rb +1 -23
- data/lib/mongoid/relations/builders/referenced/one.rb +1 -1
- data/lib/mongoid/relations/cascading.rb +5 -3
- data/lib/mongoid/relations/conversions.rb +35 -0
- data/lib/mongoid/relations/embedded/atomic.rb +3 -3
- data/lib/mongoid/relations/embedded/in.rb +1 -1
- data/lib/mongoid/relations/embedded/many.rb +16 -13
- data/lib/mongoid/relations/embedded/one.rb +3 -3
- data/lib/mongoid/relations/metadata.rb +19 -15
- data/lib/mongoid/relations/proxy.rb +4 -5
- data/lib/mongoid/relations/referenced/in.rb +1 -1
- data/lib/mongoid/relations/referenced/many.rb +12 -31
- data/lib/mongoid/relations/referenced/many_to_many.rb +4 -5
- data/lib/mongoid/relations/referenced/one.rb +6 -8
- data/lib/mongoid/relations/synchronization.rb +3 -5
- data/lib/mongoid/safety.rb +34 -4
- data/lib/mongoid/serialization.rb +20 -6
- data/lib/mongoid/threaded.rb +47 -0
- data/lib/mongoid/timestamps.rb +1 -0
- data/lib/mongoid/timestamps/created.rb +1 -8
- data/lib/mongoid/timestamps/timeless.rb +50 -0
- data/lib/mongoid/timestamps/updated.rb +2 -9
- data/lib/mongoid/validations.rb +0 -2
- data/lib/mongoid/validations/associated.rb +1 -2
- data/lib/mongoid/validations/uniqueness.rb +89 -36
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +5 -6
- data/lib/rails/generators/mongoid_generator.rb +1 -1
- data/lib/rails/mongoid.rb +14 -5
- metadata +27 -23
data/lib/mongoid/railtie.rb
CHANGED
@@ -95,7 +95,7 @@ module Rails #:nodoc:
|
|
95
95
|
# environments.
|
96
96
|
initializer "preload all application models" do |app|
|
97
97
|
config.to_prepare do
|
98
|
-
::Rails::Mongoid.
|
98
|
+
::Rails::Mongoid.preload_models(app) unless $rails_rake_task
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
@@ -79,7 +79,15 @@ namespace :db do
|
|
79
79
|
|
80
80
|
desc 'Create the indexes defined on your mongoid models'
|
81
81
|
task :create_indexes => :environment do
|
82
|
-
|
82
|
+
engines_models_paths = Rails.application.railties.engines.map do |engine|
|
83
|
+
engine.paths["app/models"].paths
|
84
|
+
end
|
85
|
+
root_models_paths = Rails.application.paths["app/models"]
|
86
|
+
models_paths = engines_models_paths.push(root_models_paths).flatten
|
87
|
+
|
88
|
+
models_paths.each do |path|
|
89
|
+
::Rails::Mongoid.create_indexes("#{path}/**/*.rb")
|
90
|
+
end
|
83
91
|
end
|
84
92
|
|
85
93
|
def convert_ids(obj)
|
data/lib/mongoid/relations.rb
CHANGED
@@ -3,6 +3,7 @@ require "mongoid/relations/accessors"
|
|
3
3
|
require "mongoid/relations/auto_save"
|
4
4
|
require "mongoid/relations/cascading"
|
5
5
|
require "mongoid/relations/constraint"
|
6
|
+
require "mongoid/relations/conversions"
|
6
7
|
require "mongoid/relations/cyclic"
|
7
8
|
require "mongoid/relations/proxy"
|
8
9
|
require "mongoid/relations/bindings"
|
@@ -35,14 +35,14 @@ module Mongoid # :nodoc:
|
|
35
35
|
# Execute a block in building mode.
|
36
36
|
#
|
37
37
|
# @example Execute in building mode.
|
38
|
-
#
|
38
|
+
# _building do
|
39
39
|
# relation.push(doc)
|
40
40
|
# end
|
41
41
|
#
|
42
42
|
# @return [ Object ] The return value of the block.
|
43
43
|
#
|
44
44
|
# @since 2.1.0
|
45
|
-
def
|
45
|
+
def _building
|
46
46
|
Threaded.begin_build
|
47
47
|
yield
|
48
48
|
ensure
|
@@ -65,8 +65,10 @@ module Mongoid # :nodoc:
|
|
65
65
|
def builder(name, metadata)
|
66
66
|
tap do
|
67
67
|
define_method("build_#{name}") do |*args|
|
68
|
-
|
69
|
-
|
68
|
+
attributes = args.first || {}
|
69
|
+
options = args.size > 1 ? args[1] : {}
|
70
|
+
document = Factory.build(metadata.klass, attributes, options)
|
71
|
+
_building do
|
70
72
|
send("#{name}=", document)
|
71
73
|
end
|
72
74
|
end
|
@@ -17,31 +17,9 @@ module Mongoid # :nodoc:
|
|
17
17
|
def build(type = nil)
|
18
18
|
return object unless query?
|
19
19
|
return [] if object.is_a?(Array)
|
20
|
-
crit = metadata.criteria(
|
20
|
+
crit = metadata.criteria(Conversions.flag(object, metadata))
|
21
21
|
IdentityMap.get(crit.klass, crit.selector) || crit
|
22
22
|
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
# Get the value for the foreign key in convertable or unconvertable
|
27
|
-
# form.
|
28
|
-
#
|
29
|
-
# @example Get the value.
|
30
|
-
# builder.convertable
|
31
|
-
#
|
32
|
-
# @return [ String, BSON::ObjectId ] The string or object id.
|
33
|
-
#
|
34
|
-
# @since 2.0.2
|
35
|
-
def convertable(metadata, object)
|
36
|
-
inverse = metadata.inverse_klass
|
37
|
-
if inverse.using_object_ids? || object.is_a?(BSON::ObjectId)
|
38
|
-
object
|
39
|
-
else
|
40
|
-
object.tap do |obj|
|
41
|
-
obj.unconvertable_to_bson = true if obj.is_a?(String)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
23
|
end
|
46
24
|
end
|
47
25
|
end
|
@@ -16,7 +16,7 @@ module Mongoid # :nodoc:
|
|
16
16
|
# @return [ Document ] A single document.
|
17
17
|
def build(type = nil)
|
18
18
|
return object unless query?
|
19
|
-
criteria = metadata.criteria(object)
|
19
|
+
criteria = metadata.criteria(Conversions.flag(object, metadata))
|
20
20
|
IdentityMap.get(criteria.klass, criteria.selector) || criteria.first
|
21
21
|
end
|
22
22
|
end
|
@@ -26,9 +26,11 @@ module Mongoid # :nodoc:
|
|
26
26
|
# @since 2.0.0.rc.1
|
27
27
|
def cascade!
|
28
28
|
cascades.each do |name|
|
29
|
-
metadata
|
30
|
-
|
31
|
-
|
29
|
+
if !metadata || !metadata.versioned?
|
30
|
+
meta = relations[name]
|
31
|
+
strategy = meta.cascade_strategy
|
32
|
+
strategy.new(self, meta).cascade
|
33
|
+
end
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Relations #:nodoc:
|
4
|
+
|
5
|
+
# Contains utility methods for object id conversion.
|
6
|
+
module Conversions
|
7
|
+
extend self
|
8
|
+
|
9
|
+
# Mark the provided object as unconvertable to bson or not, and always
|
10
|
+
# return the provided object.
|
11
|
+
#
|
12
|
+
# @example Flag the object.
|
13
|
+
# Conversions.flag(metadata, 15)
|
14
|
+
#
|
15
|
+
# @param [ Object ] object The object to flag.
|
16
|
+
# @param [ Metadata ] The relation metadata.
|
17
|
+
#
|
18
|
+
# @return [ Object ] The provided object.
|
19
|
+
#
|
20
|
+
# @since 2.3.0
|
21
|
+
def flag(object, metadata)
|
22
|
+
inverse = metadata.inverse_klass
|
23
|
+
if inverse.using_object_ids? || object.is_a?(BSON::ObjectId)
|
24
|
+
object
|
25
|
+
else
|
26
|
+
object.tap do |obj|
|
27
|
+
if obj.is_a?(String)
|
28
|
+
obj.unconvertable_to_bson = true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -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(root_class) ||
|
59
|
+
Threaded.set_update_consumer(root_class, 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(root_class, nil)
|
65
65
|
updater.execute(collection)
|
66
66
|
end
|
67
67
|
end
|
@@ -26,7 +26,7 @@ module Mongoid # :nodoc:
|
|
26
26
|
args.flatten.each do |doc|
|
27
27
|
next unless doc
|
28
28
|
append(doc)
|
29
|
-
doc.save if persistable? && !
|
29
|
+
doc.save if persistable? && !_assigning?
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -40,11 +40,12 @@ module Mongoid # :nodoc:
|
|
40
40
|
# person.people.build(:name => "Bozo")
|
41
41
|
#
|
42
42
|
# @param [ Hash ] attributes The attributes to build the document with.
|
43
|
+
# @param [ Hash ] options The scoped assignment options.
|
43
44
|
# @param [ Class ] type Optional class to build the document with.
|
44
45
|
#
|
45
46
|
# @return [ Document ] The new document.
|
46
|
-
def build(attributes = {}, type = nil)
|
47
|
-
Factory.build(type || metadata.klass, attributes).tap do |doc|
|
47
|
+
def build(attributes = {}, options = {}, type = nil)
|
48
|
+
Factory.build(type || metadata.klass, attributes, options).tap do |doc|
|
48
49
|
doc.identify
|
49
50
|
append(doc)
|
50
51
|
yield(doc) if block_given?
|
@@ -86,11 +87,12 @@ module Mongoid # :nodoc:
|
|
86
87
|
# person.movies.create(:name => "Bozo")
|
87
88
|
#
|
88
89
|
# @param [ Hash ] attributes The attributes to build the document with.
|
90
|
+
# @param [ Hash ] options The scoped assignment options.
|
89
91
|
# @param [ Class ] type Optional class to create the document with.
|
90
92
|
#
|
91
93
|
# @return [ Document ] The newly created document.
|
92
|
-
def create(attributes = {}, type = nil, &block)
|
93
|
-
build(attributes, type, &block).tap { |doc| doc.save }
|
94
|
+
def create(attributes = {}, options = {}, type = nil, &block)
|
95
|
+
build(attributes, options, type, &block).tap { |doc| doc.save }
|
94
96
|
end
|
95
97
|
|
96
98
|
# Create a new document in the relation. This is essentially the same
|
@@ -101,13 +103,14 @@ module Mongoid # :nodoc:
|
|
101
103
|
# person.addresses.create!(:street => "Unter der Linden")</tt>
|
102
104
|
#
|
103
105
|
# @param [ Hash ] attributes The attributes to build the document with.
|
106
|
+
# @param [ Hash ] options The scoped assignment options.
|
104
107
|
# @param [ Class ] type Optional class to create the document with.
|
105
108
|
#
|
106
109
|
# @raise [ Errors::Validations ] If a validation error occured.
|
107
110
|
#
|
108
111
|
# @return [ Document ] The newly created document.
|
109
|
-
def create!(attributes = {}, type = nil, &block)
|
110
|
-
build(attributes, type, &block).tap { |doc| doc.save! }
|
112
|
+
def create!(attributes = {}, options = {}, type = nil, &block)
|
113
|
+
build(attributes, options, type, &block).tap { |doc| doc.save! }
|
111
114
|
end
|
112
115
|
|
113
116
|
# Delete the supplied document from the target. This method is proxied
|
@@ -124,7 +127,7 @@ module Mongoid # :nodoc:
|
|
124
127
|
def delete(document)
|
125
128
|
target.delete_one(document).tap do |doc|
|
126
129
|
if doc && !binding?
|
127
|
-
if
|
130
|
+
if _assigning?
|
128
131
|
base.add_atomic_pull(doc)
|
129
132
|
else
|
130
133
|
doc.delete(:suppress => true)
|
@@ -232,7 +235,7 @@ module Mongoid # :nodoc:
|
|
232
235
|
def substitute(replacement)
|
233
236
|
tap do |proxy|
|
234
237
|
if replacement.blank?
|
235
|
-
if
|
238
|
+
if _assigning? && !proxy.empty?
|
236
239
|
base.atomic_unsets.push(proxy.first.atomic_path)
|
237
240
|
end
|
238
241
|
proxy.clear
|
@@ -242,13 +245,13 @@ module Mongoid # :nodoc:
|
|
242
245
|
replacement = Many.builder(metadata, replacement).build
|
243
246
|
end
|
244
247
|
proxy.target = replacement.compact
|
245
|
-
if
|
248
|
+
if _assigning?
|
246
249
|
base.delayed_atomic_sets[metadata.name.to_s] = proxy.as_document
|
247
250
|
end
|
248
251
|
proxy.target.each_with_index do |doc, index|
|
249
252
|
integrate(doc)
|
250
253
|
doc._index = index
|
251
|
-
doc.save if base.persisted? && !
|
254
|
+
doc.save if base.persisted? && !_assigning?
|
252
255
|
end
|
253
256
|
end
|
254
257
|
end
|
@@ -400,7 +403,7 @@ module Mongoid # :nodoc:
|
|
400
403
|
criteria.size.tap do
|
401
404
|
criteria.each do |doc|
|
402
405
|
target.delete_one(doc)
|
403
|
-
doc.send(method, :suppress => true) unless
|
406
|
+
doc.send(method, :suppress => true) unless _assigning?
|
404
407
|
unbind_one(doc)
|
405
408
|
end
|
406
409
|
reindex
|
@@ -515,7 +518,7 @@ module Mongoid # :nodoc:
|
|
515
518
|
#
|
516
519
|
# @since 2.1.0
|
517
520
|
def valid_options
|
518
|
-
[ :as, :cyclic, :order, :versioned ]
|
521
|
+
[ :as, :cascade_callbacks, :cyclic, :order, :versioned ]
|
519
522
|
end
|
520
523
|
|
521
524
|
# Get the default validation setting for the relation. Determines if
|
@@ -36,7 +36,7 @@ module Mongoid # :nodoc:
|
|
36
36
|
# @since 2.0.0.rc.1
|
37
37
|
def substitute(replacement)
|
38
38
|
tap do |proxy|
|
39
|
-
if
|
39
|
+
if _assigning?
|
40
40
|
base.atomic_unsets.push(proxy.atomic_path)
|
41
41
|
else
|
42
42
|
proxy.delete if persistable?
|
@@ -73,7 +73,7 @@ module Mongoid # :nodoc:
|
|
73
73
|
#
|
74
74
|
# @since 2.1.0
|
75
75
|
def persistable?
|
76
|
-
base.persisted? && !binding? && !
|
76
|
+
base.persisted? && !binding? && !_building? && !_assigning?
|
77
77
|
end
|
78
78
|
|
79
79
|
class << self
|
@@ -183,7 +183,7 @@ module Mongoid # :nodoc:
|
|
183
183
|
#
|
184
184
|
# @since 2.1.0
|
185
185
|
def valid_options
|
186
|
-
[ :as, :cyclic ]
|
186
|
+
[ :as, :cascade_callbacks, :cyclic ]
|
187
187
|
end
|
188
188
|
|
189
189
|
# Get the default validation setting for the relation. Determines if
|
@@ -89,6 +89,19 @@ module Mongoid # :nodoc:
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
# Is this an embedded relations that allows callbacks to cascade down to
|
93
|
+
# it?
|
94
|
+
#
|
95
|
+
# @example Does the relation have cascading callbacks?
|
96
|
+
# metadata.cascading_callbacks?
|
97
|
+
#
|
98
|
+
# @return [ true, false ] If the relation cascades callbacks.
|
99
|
+
#
|
100
|
+
# @since 2.3.0
|
101
|
+
def cascading_callbacks?
|
102
|
+
!!self[:cascade_callbacks]
|
103
|
+
end
|
104
|
+
|
92
105
|
# Returns the name of the class that this relation contains. If the
|
93
106
|
# class_name was provided as an option this will return that, otherwise
|
94
107
|
# it will determine the name from the name property.
|
@@ -189,7 +202,10 @@ module Mongoid # :nodoc:
|
|
189
202
|
#
|
190
203
|
# @since 2.2.0
|
191
204
|
def eager_load(criteria)
|
192
|
-
relation.eager_load(
|
205
|
+
relation.eager_load(
|
206
|
+
self,
|
207
|
+
criteria.clone.tap { |crit| crit.inclusions.clear }
|
208
|
+
)
|
193
209
|
end
|
194
210
|
|
195
211
|
# Will determine if the relation is an embedded one or not. Currently
|
@@ -229,19 +245,6 @@ module Mongoid # :nodoc:
|
|
229
245
|
!!extension
|
230
246
|
end
|
231
247
|
|
232
|
-
# Does this metadata have a forced nil inverse_of defined. (Used in many
|
233
|
-
# to manies)
|
234
|
-
#
|
235
|
-
# @example Is this a forced nil inverse?
|
236
|
-
# metadata.forced_nil_inverse?
|
237
|
-
#
|
238
|
-
# @return [ true, false ] If inverse_of has been explicitly set to nil.
|
239
|
-
#
|
240
|
-
# @since 2.3.3
|
241
|
-
def forced_nil_inverse?
|
242
|
-
has_key?(:inverse_of) && inverse_of.nil?
|
243
|
-
end
|
244
|
-
|
245
248
|
# Handles all the logic for figuring out what the foreign_key is for each
|
246
249
|
# relations query. The logic is as follows:
|
247
250
|
#
|
@@ -773,7 +776,7 @@ module Mongoid # :nodoc:
|
|
773
776
|
#
|
774
777
|
# @since 2.0.0.rc.1
|
775
778
|
def determine_cyclic_inverse
|
776
|
-
underscored = class_name.underscore
|
779
|
+
underscored = class_name.demodulize.underscore
|
777
780
|
klass.relations.each_pair do |key, meta|
|
778
781
|
if key =~ /#{underscored.singularize}|#{underscored.pluralize}/ &&
|
779
782
|
meta.relation != relation
|
@@ -823,6 +826,7 @@ module Mongoid # :nodoc:
|
|
823
826
|
default = klass.relations[inverse_klass.name.underscore]
|
824
827
|
return default.name if default
|
825
828
|
klass.relations.each_pair do |key, meta|
|
829
|
+
next if meta.versioned? || meta.name == name
|
826
830
|
if meta.class_name == inverse_class_name
|
827
831
|
return key.to_sym
|
828
832
|
end
|
@@ -17,7 +17,6 @@ module Mongoid # :nodoc:
|
|
17
17
|
# Backwards compatibility with Mongoid beta releases.
|
18
18
|
delegate :klass, :to => :metadata
|
19
19
|
delegate :bind_one, :unbind_one, :to => :binding
|
20
|
-
delegate :collection_name, :to => :base
|
21
20
|
|
22
21
|
# Convenience for setting the target and the metadata properties since
|
23
22
|
# all proxies will need to do this.
|
@@ -54,12 +53,12 @@ module Mongoid # :nodoc:
|
|
54
53
|
# Is the current thread in assigning mode?
|
55
54
|
#
|
56
55
|
# @example Is the current thread in assigning mode?
|
57
|
-
# proxy.
|
56
|
+
# proxy._assigning?
|
58
57
|
#
|
59
58
|
# @return [ true, false ] If the thread is assigning.
|
60
59
|
#
|
61
60
|
# @since 2.1.0
|
62
|
-
def
|
61
|
+
def _assigning?
|
63
62
|
Threaded.assigning?
|
64
63
|
end
|
65
64
|
|
@@ -78,12 +77,12 @@ module Mongoid # :nodoc:
|
|
78
77
|
# Is the current thread in building mode?
|
79
78
|
#
|
80
79
|
# @example Is the current thread in building mode?
|
81
|
-
# proxy.
|
80
|
+
# proxy._building?
|
82
81
|
#
|
83
82
|
# @return [ true, false ] If the thread is building.
|
84
83
|
#
|
85
84
|
# @since 2.1.0
|
86
|
-
def
|
85
|
+
def _building?
|
87
86
|
Threaded.building?
|
88
87
|
end
|
89
88
|
|