mongoid 2.2.6 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|