mongoid 3.0.6 → 3.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +57 -1
- data/lib/config/locales/en.yml +6 -2
- data/lib/mongoid/attributes.rb +1 -1
- data/lib/mongoid/attributes/processing.rb +58 -11
- data/lib/mongoid/config.rb +13 -0
- data/lib/mongoid/contextual/map_reduce.rb +1 -1
- data/lib/mongoid/contextual/memory.rb +5 -4
- data/lib/mongoid/contextual/mongo.rb +2 -2
- data/lib/mongoid/criteria.rb +10 -1
- data/lib/mongoid/dirty.rb +0 -1
- data/lib/mongoid/document.rb +2 -1
- data/lib/mongoid/extensions/array.rb +1 -1
- data/lib/mongoid/extensions/big_decimal.rb +15 -0
- data/lib/mongoid/extensions/hash.rb +18 -0
- data/lib/mongoid/factory.rb +1 -1
- data/lib/mongoid/fields.rb +31 -0
- data/lib/mongoid/hierarchy.rb +15 -0
- data/lib/mongoid/indexes.rb +22 -2
- data/lib/mongoid/indexes/validators/options.rb +2 -2
- data/lib/mongoid/multi_parameter_attributes.rb +1 -1
- data/lib/mongoid/nested_attributes.rb +1 -1
- data/lib/mongoid/persistence.rb +1 -1
- data/lib/mongoid/persistence/insertion.rb +1 -0
- data/lib/mongoid/railtie.rb +1 -15
- data/lib/mongoid/relations/accessors.rb +1 -1
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +17 -6
- data/lib/mongoid/relations/builders/nested_attributes/one.rb +41 -50
- data/lib/mongoid/relations/embedded/batchable.rb +1 -1
- data/lib/mongoid/relations/metadata.rb +1 -0
- data/lib/mongoid/relations/referenced/many.rb +5 -1
- data/lib/mongoid/relations/targets/enumerable.rb +10 -0
- data/lib/mongoid/threaded.rb +22 -4
- data/lib/mongoid/validations/uniqueness.rb +1 -2
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +13 -1
- metadata +3 -3
data/CHANGELOG.md
CHANGED
@@ -3,7 +3,63 @@
|
|
3
3
|
For instructions on upgrading to newer versions, visit
|
4
4
|
[mongoid.org](http://mongoid.org/docs/upgrading.html).
|
5
5
|
|
6
|
-
## 3.0.
|
6
|
+
## 3.0.9
|
7
|
+
|
8
|
+
### Resolved Issues
|
9
|
+
|
10
|
+
* \#2463 Fixed the broken `rails g mongoid:config` from a fresh repo.
|
11
|
+
|
12
|
+
* \#2456 The descendants cache is now reset when the document is inherited
|
13
|
+
again. (Kostyantyn Stepanyuk)
|
14
|
+
|
15
|
+
* \#2453 `Model#write_attribute` now properly works with aliased fields.
|
16
|
+
(Campbell Allen)
|
17
|
+
|
18
|
+
* \#2444 Removed extra dirty methods creation call. (Kostyantyn Stepanyuk)
|
19
|
+
|
20
|
+
* \#2440/\#2435 Pass mass assignment options down to children when setting via
|
21
|
+
nested attributes or embedded documents.
|
22
|
+
|
23
|
+
* \#2439 Fixed memory leak in threaded selection of returned fields.
|
24
|
+
(Tim Olsen)
|
25
|
+
|
26
|
+
* mongoid/moped\#82 Aliased fields now work with `Criteria#distinct`.
|
27
|
+
|
28
|
+
* \#2423 Fixed embedded document's `update_all` to perform the correct $set
|
29
|
+
when using off a criteria.
|
30
|
+
|
31
|
+
* \#2414 Index definitions now respect aliased fields.
|
32
|
+
|
33
|
+
* \#2413 Enumerable targets now properly return enumerators when no blocks
|
34
|
+
are provided. (Andrew Smith)
|
35
|
+
|
36
|
+
* \#2411 BigDecimal fields are properly stored as strings when mongoizing
|
37
|
+
integers and floats.
|
38
|
+
|
39
|
+
* \#2409 Don't warn about missing mongoid.yml if configured programatically.
|
40
|
+
|
41
|
+
* \#2403 Return false on `update_all` of an embeds many with no documents.
|
42
|
+
|
43
|
+
* \#2401 Bring back the ability to merge a criteria with a hash.
|
44
|
+
|
45
|
+
* \#2399 Reject blank id values on has_many `Model#object_ids=`.
|
46
|
+
(Tiago Rafael Godinho)
|
47
|
+
|
48
|
+
* \#2393 Ensure `inverse_of` is respected when using polymorphic relations.
|
49
|
+
|
50
|
+
* \#2388 Map/reduce properly uses `sort` instead of `orderby` in the execution
|
51
|
+
of the command. (Alex Tsibulya)
|
52
|
+
|
53
|
+
* \#2386 Allow geo haystack and bits parameters in indexes. (Bradley Rees)
|
54
|
+
|
55
|
+
* \#2380 `Model#becomes` now properly copies over dirty attributes.
|
56
|
+
|
57
|
+
* \#2331 Don't double push child documents when extra saves are called in an
|
58
|
+
after_create callback.
|
59
|
+
|
60
|
+
## 3.0.8 (Yanked)
|
61
|
+
|
62
|
+
## 3.0.6
|
7
63
|
|
8
64
|
### Resolved Issues
|
9
65
|
|
data/lib/config/locales/en.yml
CHANGED
@@ -152,8 +152,12 @@ en:
|
|
152
152
|
\_\_drop_dups: true|false\n
|
153
153
|
\_\_name: 'index_name'\n
|
154
154
|
\_\_sparse: true|false\n
|
155
|
-
\_\_unique: true|false\n
|
156
|
-
|
155
|
+
\_\_unique: true|false\n
|
156
|
+
\_\_min: 1\n
|
157
|
+
\_\_max: 1\n
|
158
|
+
\_\_bits: 26\n
|
159
|
+
\_\_bucket_size : 1\n
|
160
|
+
Valid types are: 1, -1, '2d', 'geoHaystack'\n\n
|
157
161
|
Example:\n
|
158
162
|
\_\_class Band\n
|
159
163
|
\_\_\_\_include Mongoid::Document\n
|
data/lib/mongoid/attributes.rb
CHANGED
@@ -19,19 +19,41 @@ module Mongoid
|
|
19
19
|
#
|
20
20
|
# @since 2.0.0.rc.7
|
21
21
|
def process_attributes(attrs = nil, role = :default, guard_protected_attributes = true)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
with_mass_assignment(role, guard_protected_attributes) do
|
23
|
+
attrs ||= {}
|
24
|
+
if !attrs.empty?
|
25
|
+
attrs = sanitize_for_mass_assignment(attrs, role) if guard_protected_attributes
|
26
|
+
attrs.each_pair do |key, value|
|
27
|
+
next if pending_attribute?(key, value)
|
28
|
+
process_attribute(key, value)
|
29
|
+
end
|
28
30
|
end
|
31
|
+
yield self if block_given?
|
32
|
+
process_pending
|
29
33
|
end
|
30
|
-
yield self if block_given?
|
31
|
-
process_pending
|
32
34
|
end
|
33
35
|
|
34
|
-
|
36
|
+
private
|
37
|
+
|
38
|
+
# Get the current mass assignment options for this model.
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
# @return [ Hash ] The mass assignment options.
|
43
|
+
#
|
44
|
+
# @since 3.0.7
|
45
|
+
def mass_assignment_options
|
46
|
+
@mass_assignment_options ||= {}
|
47
|
+
end
|
48
|
+
|
49
|
+
# Set the mass assignment options for the current model.
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
#
|
53
|
+
# @return [ Hash ] The mass assignment options.
|
54
|
+
#
|
55
|
+
# @since 3.0.7
|
56
|
+
attr_writer :mass_assignment_options
|
35
57
|
|
36
58
|
# If the key provided is the name of a relation or a nested attribute, we
|
37
59
|
# need to wait until all other attributes are set before processing
|
@@ -121,6 +143,8 @@ module Mongoid
|
|
121
143
|
# @example Process the pending items.
|
122
144
|
# document.process_pending
|
123
145
|
#
|
146
|
+
# @param [ Hash ] options The mass assignment options.
|
147
|
+
#
|
124
148
|
# @since 2.0.0.rc.7
|
125
149
|
def process_pending
|
126
150
|
process_nested and process_relations
|
@@ -133,18 +157,41 @@ module Mongoid
|
|
133
157
|
# @example Process the relations.
|
134
158
|
# document.process_relations
|
135
159
|
#
|
160
|
+
# @param [ Hash ] options The mass assignment options.
|
161
|
+
#
|
136
162
|
# @since 2.0.0.rc.7
|
137
163
|
def process_relations
|
138
164
|
pending_relations.each_pair do |name, value|
|
139
165
|
metadata = relations[name]
|
140
166
|
if value.is_a?(Hash)
|
141
|
-
metadata.nested_builder(value, {}).build(self)
|
167
|
+
metadata.nested_builder(value, {}).build(self, mass_assignment_options)
|
142
168
|
else
|
143
169
|
send("#{name}=", value)
|
144
170
|
end
|
145
171
|
end
|
146
172
|
end
|
173
|
+
|
174
|
+
# Execute the block with the provided mass assignment options set.
|
175
|
+
#
|
176
|
+
# @api private
|
177
|
+
#
|
178
|
+
# @example Execute with mass assignment.
|
179
|
+
# model.with_mass_assignment(:default, true)
|
180
|
+
#
|
181
|
+
# @param [ Symbol ] role The role.
|
182
|
+
# @param [ true, false ] guard_protected_attributes To enable mass
|
183
|
+
# assignment.
|
184
|
+
#
|
185
|
+
# @since 3.0.7
|
186
|
+
def with_mass_assignment(role, guard_protected_attributes)
|
187
|
+
begin
|
188
|
+
self.mass_assignment_options =
|
189
|
+
{ as: role, without_protection: !guard_protected_attributes }
|
190
|
+
yield
|
191
|
+
ensure
|
192
|
+
self.mass_assignment_options = nil
|
193
|
+
end
|
194
|
+
end
|
147
195
|
end
|
148
196
|
end
|
149
197
|
end
|
150
|
-
|
data/lib/mongoid/config.rb
CHANGED
@@ -26,6 +26,19 @@ module Mongoid
|
|
26
26
|
option :use_activesupport_time_zone, default: true
|
27
27
|
option :use_utc, default: false
|
28
28
|
|
29
|
+
# Has Mongoid been configured? This is checking that at least a valid
|
30
|
+
# session config exists.
|
31
|
+
#
|
32
|
+
# @example Is Mongoid configured?
|
33
|
+
# config.configured?
|
34
|
+
#
|
35
|
+
# @return [ true, false ] If Mongoid is configured.
|
36
|
+
#
|
37
|
+
# @since 3.0.9
|
38
|
+
def configured?
|
39
|
+
sessions.has_key?(:default)
|
40
|
+
end
|
41
|
+
|
29
42
|
# Connect to the provided database name on the default session.
|
30
43
|
#
|
31
44
|
# @note Use only in development or test environments for convenience.
|
@@ -216,7 +216,7 @@ module Mongoid
|
|
216
216
|
def apply_criteria_options
|
217
217
|
command[:query] = criteria.selector
|
218
218
|
if sort = criteria.options[:sort]
|
219
|
-
command[:
|
219
|
+
command[:sort] = sort
|
220
220
|
end
|
221
221
|
if limit = criteria.options[:limit]
|
222
222
|
command[:limit] = limit
|
@@ -281,14 +281,15 @@ module Mongoid
|
|
281
281
|
#
|
282
282
|
# @since 3.0.4
|
283
283
|
def update_documents(attributes, docs)
|
284
|
-
return false
|
285
|
-
updates = {}
|
284
|
+
return false if !attributes || docs.empty?
|
285
|
+
updates = { "$set" => {}}
|
286
286
|
docs.each do |doc|
|
287
287
|
@selector ||= root.atomic_selector
|
288
288
|
doc.write_attributes(attributes)
|
289
|
-
updates.merge!(doc.
|
289
|
+
updates["$set"].merge!(doc.atomic_updates["$set"])
|
290
|
+
doc.move_changes
|
290
291
|
end
|
291
|
-
collection.find(selector).update(
|
292
|
+
collection.find(selector).update(updates)
|
292
293
|
end
|
293
294
|
|
294
295
|
# Get the limiting value.
|
@@ -113,7 +113,7 @@ module Mongoid
|
|
113
113
|
#
|
114
114
|
# @since 3.0.0
|
115
115
|
def distinct(field)
|
116
|
-
query.distinct(field)
|
116
|
+
query.distinct(klass.database_field_name(field))
|
117
117
|
end
|
118
118
|
|
119
119
|
# Iterate over the context. If provided a block, yield to a Mongoid
|
@@ -602,7 +602,7 @@ module Mongoid
|
|
602
602
|
Threaded.set_selection(criteria.object_id, fields) unless fields.blank?
|
603
603
|
yield
|
604
604
|
ensure
|
605
|
-
Threaded.
|
605
|
+
Threaded.delete_selection(criteria.object_id)
|
606
606
|
end
|
607
607
|
end
|
608
608
|
|
data/lib/mongoid/criteria.rb
CHANGED
@@ -320,7 +320,7 @@ module Mongoid
|
|
320
320
|
# @since 1.0.0
|
321
321
|
def initialize(klass)
|
322
322
|
@klass = klass
|
323
|
-
super(klass.aliased_fields, klass.fields)
|
323
|
+
klass ? super(klass.aliased_fields, klass.fields) : super({}, {})
|
324
324
|
end
|
325
325
|
|
326
326
|
# Eager loads all the provided relations. Will load all the documents
|
@@ -390,6 +390,15 @@ module Mongoid
|
|
390
390
|
# @example Merge the criteria with another criteria.
|
391
391
|
# criteri.merge(other_criteria)
|
392
392
|
#
|
393
|
+
# @example Merge the criteria with a hash. The hash must contain a klass
|
394
|
+
# key and the key/value pairs correspond to method names/args.
|
395
|
+
|
396
|
+
# criteria.merge({
|
397
|
+
# klass: Band,
|
398
|
+
# where: { name: "Depeche Mode" },
|
399
|
+
# order_by: { name: 1 }
|
400
|
+
# })
|
401
|
+
#
|
393
402
|
# @param [ Criteria ] other The other criterion to merge with.
|
394
403
|
#
|
395
404
|
# @return [ Criteria ] A cloned self.
|
data/lib/mongoid/dirty.rb
CHANGED
data/lib/mongoid/document.rb
CHANGED
@@ -215,7 +215,8 @@ module Mongoid
|
|
215
215
|
unless klass.include?(Mongoid::Document)
|
216
216
|
raise ArgumentError, "A class which includes Mongoid::Document is expected"
|
217
217
|
end
|
218
|
-
became = klass.
|
218
|
+
became = klass.new(as_document.__deep_copy__)
|
219
|
+
became.instance_variable_set(:@changed_attributes, changed_attributes)
|
219
220
|
became.instance_variable_set(:@errors, errors)
|
220
221
|
became.instance_variable_set(:@new_record, new_record?)
|
221
222
|
became.instance_variable_set(:@destroyed, destroyed?)
|
@@ -45,6 +45,21 @@ module Mongoid
|
|
45
45
|
object.numeric? ? ::BigDecimal.new(object.to_s) : object
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
49
|
+
# Mongoize an object of any type to how it's stored in the db as a big
|
50
|
+
# decimal.
|
51
|
+
#
|
52
|
+
# @example Mongoize the object.
|
53
|
+
# BigDecimal.mongoize(123)
|
54
|
+
#
|
55
|
+
# @param [ Object ] object The object to Mongoize
|
56
|
+
#
|
57
|
+
# @return [ String ] The mongoized object.
|
58
|
+
#
|
59
|
+
# @since 3.0.7
|
60
|
+
def mongoize(object)
|
61
|
+
object ? object.to_s : object
|
62
|
+
end
|
48
63
|
end
|
49
64
|
end
|
50
65
|
end
|
@@ -97,6 +97,24 @@ module Mongoid
|
|
97
97
|
true
|
98
98
|
end
|
99
99
|
|
100
|
+
# Convert this hash to a criteria. Will iterate over each keys in the
|
101
|
+
# hash which must correspond to method on a criteria object. The hash
|
102
|
+
# must also include a "klass" key.
|
103
|
+
#
|
104
|
+
# @example Convert the hash to a criteria.
|
105
|
+
# { klass: Band, where: { name: "Depeche Mode" }.to_criteria
|
106
|
+
#
|
107
|
+
# @return [ Criteria ] The criteria.
|
108
|
+
#
|
109
|
+
# @since 3.0.7
|
110
|
+
def to_criteria
|
111
|
+
criteria = Criteria.new(delete(:klass) || delete("klass"))
|
112
|
+
each_pair do |method, args|
|
113
|
+
criteria = criteria.__send__(method, args)
|
114
|
+
end
|
115
|
+
criteria
|
116
|
+
end
|
117
|
+
|
100
118
|
module ClassMethods
|
101
119
|
|
102
120
|
# Turn the object from the ruby type we deal with to a Mongo friendly
|
data/lib/mongoid/factory.rb
CHANGED
@@ -12,7 +12,7 @@ module Mongoid
|
|
12
12
|
#
|
13
13
|
# @param [ Class ] klass The class to instantiate from if _type is not present.
|
14
14
|
# @param [ Hash ] attributes The document attributes.
|
15
|
-
# @param [ Hash ]
|
15
|
+
# @param [ Hash ] options The mass assignment scoping options.
|
16
16
|
#
|
17
17
|
# @return [ Document ] The instantiated document.
|
18
18
|
def build(klass, attributes = nil, options = {})
|
data/lib/mongoid/fields.rb
CHANGED
@@ -109,6 +109,21 @@ module Mongoid
|
|
109
109
|
self.class.attribute_names
|
110
110
|
end
|
111
111
|
|
112
|
+
# Get the name of the provided field as it is stored in the database.
|
113
|
+
# Used in determining if the field is aliased or not.
|
114
|
+
#
|
115
|
+
# @example Get the database field name.
|
116
|
+
# model.database_field_name(:authorization)
|
117
|
+
#
|
118
|
+
# @param [ String, Symbol ] name The name to get.
|
119
|
+
#
|
120
|
+
# @return [ String ] The name of the field as it's stored in the db.
|
121
|
+
#
|
122
|
+
# @since 3.0.7
|
123
|
+
def database_field_name(name)
|
124
|
+
self.class.database_field_name(name)
|
125
|
+
end
|
126
|
+
|
112
127
|
# Is the document using object ids?
|
113
128
|
#
|
114
129
|
# @note Refactored from using delegate for class load performance.
|
@@ -175,6 +190,22 @@ module Mongoid
|
|
175
190
|
fields.keys
|
176
191
|
end
|
177
192
|
|
193
|
+
# Get the name of the provided field as it is stored in the database.
|
194
|
+
# Used in determining if the field is aliased or not.
|
195
|
+
#
|
196
|
+
# @example Get the database field name.
|
197
|
+
# Model.database_field_name(:authorization)
|
198
|
+
#
|
199
|
+
# @param [ String, Symbol ] name The name to get.
|
200
|
+
#
|
201
|
+
# @return [ String ] The name of the field as it's stored in the db.
|
202
|
+
#
|
203
|
+
# @since 3.0.7
|
204
|
+
def database_field_name(name)
|
205
|
+
normalized = name.to_s
|
206
|
+
aliased_fields[normalized] || normalized
|
207
|
+
end
|
208
|
+
|
178
209
|
# Defines all the fields that are accessible on the Document
|
179
210
|
# For each field that is defined, a getter and setter will be
|
180
211
|
# added as an instance method to the Document.
|
data/lib/mongoid/hierarchy.rb
CHANGED
@@ -44,6 +44,20 @@ module Mongoid
|
|
44
44
|
children
|
45
45
|
end
|
46
46
|
|
47
|
+
# Marks all children as being persisted.
|
48
|
+
#
|
49
|
+
# @example Flag all the children.
|
50
|
+
# document.flag_children_persisted
|
51
|
+
#
|
52
|
+
# @return [ Array<Document> ] The flagged children.
|
53
|
+
#
|
54
|
+
# @since 3.0.7
|
55
|
+
def flag_children_persisted
|
56
|
+
_children.each do |child|
|
57
|
+
child.new_record = false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
47
61
|
# Determines if the document is a subclass of another document.
|
48
62
|
#
|
49
63
|
# @example Check if the document is a subclass
|
@@ -141,6 +155,7 @@ module Mongoid
|
|
141
155
|
# @since 2.0.0.rc.6
|
142
156
|
def inherited(subclass)
|
143
157
|
super
|
158
|
+
@_type = nil
|
144
159
|
subclass.fields = fields.dup
|
145
160
|
subclass.pre_processed_defaults = pre_processed_defaults.dup
|
146
161
|
subclass.post_processed_defaults = post_processed_defaults.dup
|
data/lib/mongoid/indexes.rb
CHANGED
@@ -78,7 +78,7 @@ module Mongoid
|
|
78
78
|
# @since 1.0.0
|
79
79
|
def index(spec, options = nil)
|
80
80
|
Validators::Options.validate(self, spec, options || {})
|
81
|
-
index_options[spec] = normalize_index_options(options)
|
81
|
+
index_options[normalize_spec(spec)] = normalize_index_options(options)
|
82
82
|
end
|
83
83
|
|
84
84
|
private
|
@@ -88,7 +88,7 @@ module Mongoid
|
|
88
88
|
# @api private
|
89
89
|
#
|
90
90
|
# @example Normalize the index options.
|
91
|
-
#
|
91
|
+
# Model.normalize_index_options(drop_dups: true)
|
92
92
|
#
|
93
93
|
# @param [ Hash ] options The index options.
|
94
94
|
#
|
@@ -98,8 +98,28 @@ module Mongoid
|
|
98
98
|
def normalize_index_options(options)
|
99
99
|
opts = options || {}
|
100
100
|
opts[:dropDups] = opts.delete(:drop_dups) if opts.has_key?(:drop_dups)
|
101
|
+
opts[:bucketSize] = opts.delete(:bucket_size) if opts.has_key?(:bucket_size)
|
101
102
|
opts
|
102
103
|
end
|
104
|
+
|
105
|
+
# Normalize the spec, in case aliased fields are provided.
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
#
|
109
|
+
# @example Normalize the spec.
|
110
|
+
# Model.normalize_spec(name: 1)
|
111
|
+
#
|
112
|
+
# @param [ Hash ] spec The index specification.
|
113
|
+
#
|
114
|
+
# @return [ Hash ] The normalized specification.
|
115
|
+
#
|
116
|
+
# @since 3.0.7
|
117
|
+
def normalize_spec(spec)
|
118
|
+
spec.inject({}) do |normalized, (name, direction)|
|
119
|
+
normalized[database_field_name(name).to_sym] = direction
|
120
|
+
normalized
|
121
|
+
end
|
122
|
+
end
|
103
123
|
end
|
104
124
|
end
|
105
125
|
end
|
@@ -7,8 +7,8 @@ module Mongoid
|
|
7
7
|
module Options
|
8
8
|
extend self
|
9
9
|
|
10
|
-
VALID_OPTIONS = [ :background, :drop_dups, :name, :sparse, :unique, :max, :min ]
|
11
|
-
VALID_TYPES = [ 1, -1, "2d" ]
|
10
|
+
VALID_OPTIONS = [ :background, :drop_dups, :name, :sparse, :unique, :max, :min, :bits, :bucket_size ]
|
11
|
+
VALID_TYPES = [ 1, -1, "2d", "geoHaystack" ]
|
12
12
|
|
13
13
|
# Validate the index specification.
|
14
14
|
#
|
@@ -66,7 +66,7 @@ module Mongoid
|
|
66
66
|
multi_parameter_attributes.each_pair do |key, values|
|
67
67
|
begin
|
68
68
|
values = (values.keys.min..values.keys.max).map { |i| values[i] }
|
69
|
-
field = self.class.fields[
|
69
|
+
field = self.class.fields[database_field_name(key)]
|
70
70
|
attributes[key] = instantiate_object(field, values)
|
71
71
|
rescue => e
|
72
72
|
errors << Errors::AttributeAssignmentError.new(
|
@@ -52,7 +52,7 @@ module Mongoid
|
|
52
52
|
autosave(metadata.merge!(autosave: true))
|
53
53
|
re_define_method(meth) do |attrs|
|
54
54
|
_assigning do
|
55
|
-
metadata.nested_builder(attrs, options).build(self)
|
55
|
+
metadata.nested_builder(attrs, options).build(self, mass_assignment_options)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
data/lib/mongoid/persistence.rb
CHANGED
@@ -159,7 +159,7 @@ module Mongoid
|
|
159
159
|
unless attribute_writable?(normalized)
|
160
160
|
raise Errors::ReadonlyAttribute.new(normalized, value)
|
161
161
|
end
|
162
|
-
write_attribute(
|
162
|
+
write_attribute(database_field_name(normalized), value)
|
163
163
|
save(validate: false)
|
164
164
|
end
|
165
165
|
|
data/lib/mongoid/railtie.rb
CHANGED
@@ -60,20 +60,6 @@ module Rails
|
|
60
60
|
|
61
61
|
# Initialize Mongoid. This will look for a mongoid.yml in the config
|
62
62
|
# directory and configure mongoid appropriately.
|
63
|
-
#
|
64
|
-
# @example mongoid.yml
|
65
|
-
#
|
66
|
-
# development:
|
67
|
-
# host: localhost
|
68
|
-
# database: mongoid
|
69
|
-
# slaves:
|
70
|
-
# # - host: localhost
|
71
|
-
# # port: 27018
|
72
|
-
# # - host: localhost
|
73
|
-
# # port: 27019
|
74
|
-
# allow_dynamic_fields: false
|
75
|
-
# persist_in_safe_mode: false
|
76
|
-
#
|
77
63
|
initializer "setup database" do
|
78
64
|
config_file = Rails.root.join("config", "mongoid.yml")
|
79
65
|
if config_file.file?
|
@@ -95,7 +81,7 @@ module Rails
|
|
95
81
|
# alert to create one.
|
96
82
|
initializer "warn when configuration is missing" do
|
97
83
|
config.after_initialize do
|
98
|
-
unless Rails.root.join("config", "mongoid.yml").file?
|
84
|
+
unless Rails.root.join("config", "mongoid.yml").file? || ::Mongoid.configured?
|
99
85
|
puts "\nMongoid config not found. Create a config file at: config/mongoid.yml"
|
100
86
|
puts "to generate one run: rails generate mongoid:config\n\n"
|
101
87
|
end
|
@@ -228,7 +228,7 @@ module Mongoid
|
|
228
228
|
def ids_setter(name, metadata)
|
229
229
|
ids_method = "#{name.to_s.singularize}_ids="
|
230
230
|
re_define_method(ids_method) do |ids|
|
231
|
-
send(metadata.setter, metadata.klass.find(ids))
|
231
|
+
send(metadata.setter, metadata.klass.find(ids.reject(&:blank?)))
|
232
232
|
end
|
233
233
|
self
|
234
234
|
end
|
@@ -16,18 +16,19 @@ module Mongoid
|
|
16
16
|
# many.build(person)
|
17
17
|
#
|
18
18
|
# @param [ Document ] parent The parent document of the relation.
|
19
|
+
# @param [ Hash ] options The mass assignment options.
|
19
20
|
#
|
20
21
|
# @return [ Array ] The attributes.
|
21
|
-
def build(parent)
|
22
|
+
def build(parent, options = {})
|
22
23
|
@existing = parent.send(metadata.name)
|
23
24
|
if over_limit?(attributes)
|
24
25
|
raise Errors::TooManyNestedAttributeRecords.new(existing, options[:limit])
|
25
26
|
end
|
26
27
|
attributes.each do |attrs|
|
27
28
|
if attrs.respond_to?(:with_indifferent_access)
|
28
|
-
process_attributes(parent, attrs)
|
29
|
+
process_attributes(parent, attrs, options)
|
29
30
|
else
|
30
|
-
process_attributes(parent, attrs[1])
|
31
|
+
process_attributes(parent, attrs[1], options)
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
@@ -85,11 +86,17 @@ module Mongoid
|
|
85
86
|
# Process each set of attributes one at a time for each potential
|
86
87
|
# new, existing, or ignored document.
|
87
88
|
#
|
89
|
+
# @api private
|
90
|
+
#
|
88
91
|
# @example Process the attributes
|
89
92
|
# builder.process_attributes({ "id" => 1, "street" => "Bond" })
|
90
93
|
#
|
94
|
+
# @param [ Document ] parent The parent document.
|
91
95
|
# @param [ Hash ] attrs The single document attributes to process.
|
92
|
-
|
96
|
+
# @param [ Hash ] options the mass assignment options.
|
97
|
+
#
|
98
|
+
# @since 2.0.0
|
99
|
+
def process_attributes(parent, attrs, options)
|
93
100
|
return if reject?(parent, attrs)
|
94
101
|
if id = attrs.extract_id
|
95
102
|
first = existing.first
|
@@ -100,10 +107,14 @@ module Mongoid
|
|
100
107
|
doc.destroy unless doc.embedded? || doc.destroyed?
|
101
108
|
else
|
102
109
|
attrs.delete_id
|
103
|
-
metadata.embedded?
|
110
|
+
if metadata.embedded?
|
111
|
+
doc.assign_attributes(attrs, options)
|
112
|
+
else
|
113
|
+
doc.update_attributes(attrs, options)
|
114
|
+
end
|
104
115
|
end
|
105
116
|
else
|
106
|
-
existing.push(Factory.build(metadata.klass, attrs)) unless destroyable?(attrs)
|
117
|
+
existing.push(Factory.build(metadata.klass, attrs, options)) unless destroyable?(attrs)
|
107
118
|
end
|
108
119
|
end
|
109
120
|
end
|
@@ -10,25 +10,27 @@ module Mongoid
|
|
10
10
|
# Builds the relation depending on the attributes and the options
|
11
11
|
# passed to the macro.
|
12
12
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# document, or a removal of the relation.
|
13
|
+
# @example Build a 1-1 nested document.
|
14
|
+
# one.build(person, as: :admin)
|
16
15
|
#
|
17
|
-
#
|
16
|
+
# @note This attempts to perform 3 operations, either one of an update of
|
17
|
+
# the existing relation, a replacement of the relation with a new
|
18
|
+
# document, or a removal of the relation.
|
18
19
|
#
|
19
|
-
#
|
20
|
+
# @param [ Document ] parent The parent document.
|
21
|
+
# @param [ Hash ] options The mass assignment options.
|
20
22
|
#
|
21
|
-
#
|
23
|
+
# @return [ Document ] The built document.
|
22
24
|
#
|
23
|
-
#
|
24
|
-
def build(parent)
|
25
|
+
# @since 2.0.0
|
26
|
+
def build(parent, options = {})
|
25
27
|
return if reject?(parent, attributes)
|
26
28
|
@existing = parent.send(metadata.name)
|
27
29
|
if update?
|
28
30
|
attributes.delete_id
|
29
|
-
existing.attributes
|
31
|
+
existing.assign_attributes(attributes, options)
|
30
32
|
elsif replace?
|
31
|
-
parent.send(metadata.setter, Factory.build(metadata.klass, attributes))
|
33
|
+
parent.send(metadata.setter, Factory.build(metadata.klass, attributes, options))
|
32
34
|
elsif delete?
|
33
35
|
parent.send(metadata.setter, nil)
|
34
36
|
end
|
@@ -37,19 +39,14 @@ module Mongoid
|
|
37
39
|
# Create the new builder for nested attributes on one-to-one
|
38
40
|
# relations.
|
39
41
|
#
|
40
|
-
#
|
42
|
+
# @example Instantiate the builder.
|
43
|
+
# One.new(metadata, attributes, options)
|
41
44
|
#
|
42
|
-
#
|
45
|
+
# @param [ Metadata ] metadata The relation metadata.
|
46
|
+
# @param [ Hash ] attributes The attributes hash to attempt to set.
|
47
|
+
# @param [ Hash ] options The options defined.
|
43
48
|
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
# metadata: The relation metadata
|
47
|
-
# attributes: The attributes hash to attempt to set.
|
48
|
-
# options: The options defined.
|
49
|
-
#
|
50
|
-
# Returns:
|
51
|
-
#
|
52
|
-
# A new builder.
|
49
|
+
# @since 2.0.0
|
53
50
|
def initialize(metadata, attributes, options)
|
54
51
|
@attributes = attributes.with_indifferent_access
|
55
52
|
@metadata = metadata
|
@@ -62,13 +59,14 @@ module Mongoid
|
|
62
59
|
# Is the id in the attribtues acceptable for allowing an update to
|
63
60
|
# the existing relation?
|
64
61
|
#
|
65
|
-
#
|
62
|
+
# @api private
|
66
63
|
#
|
67
|
-
#
|
64
|
+
# @example Is the id acceptable?
|
65
|
+
# one.acceptable_id?
|
68
66
|
#
|
69
|
-
#
|
67
|
+
# @return [ true, false ] If the id part of the logic will allow an update.
|
70
68
|
#
|
71
|
-
#
|
69
|
+
# @since 2.0.0
|
72
70
|
def acceptable_id?
|
73
71
|
id = convert_id(existing.class, attributes[:id])
|
74
72
|
existing.id == id || id.nil? || (existing.id != id && update_only?)
|
@@ -76,56 +74,49 @@ module Mongoid
|
|
76
74
|
|
77
75
|
# Can the existing relation be deleted?
|
78
76
|
#
|
79
|
-
#
|
77
|
+
# @example Can the existing object be deleted?
|
78
|
+
# one.delete?
|
80
79
|
#
|
81
|
-
#
|
80
|
+
# @return [ true, false ] If the relation should be deleted.
|
82
81
|
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
# True if the relation should be deleted.
|
82
|
+
# @since 2.0.0
|
86
83
|
def delete?
|
87
84
|
destroyable? && !attributes[:id].nil?
|
88
85
|
end
|
89
86
|
|
90
|
-
# Can the existing relation potentially be
|
91
|
-
#
|
92
|
-
# Example:
|
87
|
+
# Can the existing relation potentially be destroyed?
|
93
88
|
#
|
94
|
-
#
|
89
|
+
# @example Is the object destroyable?
|
90
|
+
# one.destroyable?({ :_destroy => "1" })
|
95
91
|
#
|
96
|
-
#
|
92
|
+
# @return [ true, false ] If the relation can potentially be
|
93
|
+
# destroyed.
|
97
94
|
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
# Returns:
|
101
|
-
#
|
102
|
-
# True if the relation can potentially be deleted.
|
95
|
+
# @since 2.0.0
|
103
96
|
def destroyable?
|
104
97
|
[ 1, "1", true, "true" ].include?(destroy) && allow_destroy?
|
105
98
|
end
|
106
99
|
|
107
100
|
# Is the document to be replaced?
|
108
101
|
#
|
109
|
-
#
|
102
|
+
# @example Is the document to be replaced?
|
103
|
+
# one.replace?
|
110
104
|
#
|
111
|
-
#
|
105
|
+
# @return [ true, false ] If the document should be replaced.
|
112
106
|
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
# True if the document should be replaced.
|
107
|
+
# @since 2.0.0
|
116
108
|
def replace?
|
117
109
|
!existing && !destroyable? && !attributes.blank?
|
118
110
|
end
|
119
111
|
|
120
112
|
# Should the document be updated?
|
121
113
|
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
# <tt>update?</tt>
|
114
|
+
# @example Should the document be updated?
|
115
|
+
# one.update?
|
125
116
|
#
|
126
|
-
#
|
117
|
+
# @return [ true, false ] If the object should have its attributes updated.
|
127
118
|
#
|
128
|
-
#
|
119
|
+
# @since 2.0.0
|
129
120
|
def update?
|
130
121
|
existing && !destroyable? && acceptable_id?
|
131
122
|
end
|
@@ -194,7 +194,7 @@ module Mongoid
|
|
194
194
|
docs.map do |doc|
|
195
195
|
attributes = { metadata: metadata, _parent: base }
|
196
196
|
attributes.merge!(doc)
|
197
|
-
Factory.build(klass, attributes)
|
197
|
+
Factory.build(klass, attributes, base.send(:mass_assignment_options))
|
198
198
|
end
|
199
199
|
else
|
200
200
|
docs
|
@@ -163,7 +163,11 @@ module Mongoid
|
|
163
163
|
#
|
164
164
|
# @since 2.1.0
|
165
165
|
def each
|
166
|
-
|
166
|
+
if block_given?
|
167
|
+
target.each { |doc| yield(doc) }
|
168
|
+
else
|
169
|
+
to_enum
|
170
|
+
end
|
167
171
|
end
|
168
172
|
|
169
173
|
# Determine if any documents in this relation exist in the database.
|
@@ -139,15 +139,25 @@ module Mongoid
|
|
139
139
|
# the cursor while loading the documents and then iterates over the
|
140
140
|
# _added docs.
|
141
141
|
#
|
142
|
+
# If no block is passed then it returns an enumerator containing all
|
143
|
+
# docs.
|
144
|
+
#
|
142
145
|
# @example Iterate over the enumerable.
|
143
146
|
# enumerable.each do |doc|
|
144
147
|
# puts doc
|
145
148
|
# end
|
146
149
|
#
|
150
|
+
# @example return an enumerator containing all the docs
|
151
|
+
#
|
152
|
+
# a = enumerable.each
|
153
|
+
#
|
147
154
|
# @return [ true ] That the enumerable is now _loaded.
|
148
155
|
#
|
149
156
|
# @since 2.1.0
|
150
157
|
def each
|
158
|
+
unless block_given?
|
159
|
+
return to_enum
|
160
|
+
end
|
151
161
|
if _loaded?
|
152
162
|
_loaded.each_pair do |id, doc|
|
153
163
|
yield(doc)
|
data/lib/mongoid/threaded.rb
CHANGED
@@ -301,13 +301,14 @@ module Mongoid
|
|
301
301
|
# @example Get the field selection options.
|
302
302
|
# Threaded.selection
|
303
303
|
#
|
304
|
-
# @param [
|
304
|
+
# @param [ Integer ] criteria_instance_id The criteria instance id.
|
305
305
|
#
|
306
306
|
# @return [ Hash ] The field selection.
|
307
307
|
#
|
308
308
|
# @since 2.4.4
|
309
|
-
def selection(
|
310
|
-
Thread.current["[mongoid][
|
309
|
+
def selection(criteria_instance_id)
|
310
|
+
selections = Thread.current["[mongoid][selections]"]
|
311
|
+
selections[criteria_instance_id] if selections
|
311
312
|
end
|
312
313
|
|
313
314
|
# Set the field selection on the current thread.
|
@@ -322,7 +323,24 @@ module Mongoid
|
|
322
323
|
#
|
323
324
|
# @since 2.4.4
|
324
325
|
def set_selection(criteria_instance_id, value)
|
325
|
-
Thread.current["[mongoid][
|
326
|
+
Thread.current["[mongoid][selections]"] ||= {}
|
327
|
+
Thread.current["[mongoid][selections]"][criteria_instance_id] = value
|
328
|
+
end
|
329
|
+
|
330
|
+
# Delete the field selection on the current thread.
|
331
|
+
#
|
332
|
+
# @example Delete the field selection.
|
333
|
+
# Threaded.delete_selection(Person)
|
334
|
+
#
|
335
|
+
# @param [ Integer ] criteria_instance_id The criteria instance id.
|
336
|
+
#
|
337
|
+
# @return [ Boolean ] Whether there was a field selection.
|
338
|
+
#
|
339
|
+
# @since 3.0.7
|
340
|
+
def delete_selection(criteria_instance_id)
|
341
|
+
selections = Thread.current["[mongoid][selections]"]
|
342
|
+
return false unless selections
|
343
|
+
!!selections.delete(criteria_instance_id)
|
326
344
|
end
|
327
345
|
|
328
346
|
# Get the global session override.
|
@@ -167,8 +167,7 @@ module Mongoid
|
|
167
167
|
# @since 2.3.0
|
168
168
|
def scope(criteria, document, attribute)
|
169
169
|
Array.wrap(options[:scope]).each do |item|
|
170
|
-
|
171
|
-
name = document.aliased_fields[normalized] || normalized
|
170
|
+
name = document.database_field_name(item)
|
172
171
|
criteria = criteria.where(item => document.attributes[name])
|
173
172
|
end
|
174
173
|
criteria = criteria.where(deleted_at: nil) if document.paranoid?
|
data/lib/mongoid/version.rb
CHANGED
@@ -18,7 +18,15 @@ development:
|
|
18
18
|
# Change the default consistency model to :eventual or :strong.
|
19
19
|
# :eventual will send reads to secondaries, :strong sends everything
|
20
20
|
# to master. (default: :eventual)
|
21
|
-
consistency: :
|
21
|
+
# consistency: :eventual
|
22
|
+
|
23
|
+
# How many times Moped should attempt to retry an operation after
|
24
|
+
# failure. (default: 30)
|
25
|
+
# max_retries: 30
|
26
|
+
|
27
|
+
# The time in seconds that Moped should wait before retrying an
|
28
|
+
# operation on failure. (default: 1)
|
29
|
+
# retry_interval: 1
|
22
30
|
# Configure Mongoid specific options. (optional)
|
23
31
|
options:
|
24
32
|
# Configuration for whether or not to allow access to fields that do
|
@@ -66,3 +74,7 @@ test:
|
|
66
74
|
- localhost:27017
|
67
75
|
options:
|
68
76
|
consistency: :strong
|
77
|
+
# In the test environment we lower the retries and retry interval to
|
78
|
+
# low amounts for fast failures.
|
79
|
+
max_retries: 1
|
80
|
+
retry_interval: 0
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -352,7 +352,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
352
352
|
version: '0'
|
353
353
|
segments:
|
354
354
|
- 0
|
355
|
-
hash:
|
355
|
+
hash: 3436548235215749672
|
356
356
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
357
357
|
none: false
|
358
358
|
requirements:
|