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/callbacks.rb
CHANGED
|
@@ -39,9 +39,8 @@ module Mongoid #:nodoc:
|
|
|
39
39
|
#
|
|
40
40
|
# @since 2.3.0
|
|
41
41
|
def run_callbacks(kind, *args, &block)
|
|
42
|
-
run_cascading_callbacks(cascadable_children(kind), kind, *args)
|
|
43
|
-
|
|
44
|
-
end
|
|
42
|
+
run_cascading_callbacks(cascadable_children(kind), kind, *args) {}
|
|
43
|
+
super(kind, *args, &block)
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
private
|
|
@@ -106,6 +105,7 @@ module Mongoid #:nodoc:
|
|
|
106
105
|
#
|
|
107
106
|
# @since 2.3.0
|
|
108
107
|
def cascadable_child?(kind, child)
|
|
108
|
+
return false if kind == :initialize || !child.respond_to?("_#{kind}_callbacks")
|
|
109
109
|
[ :create, :destroy ].include?(kind) || child.changed? || child.new_record?
|
|
110
110
|
end
|
|
111
111
|
|
data/lib/mongoid/collection.rb
CHANGED
|
@@ -142,12 +142,16 @@ module Mongoid #:nodoc
|
|
|
142
142
|
#
|
|
143
143
|
# @since 2.0.0
|
|
144
144
|
def update(selector, document, options = {})
|
|
145
|
-
updater = Threaded.update_consumer(
|
|
145
|
+
updater = Threaded.update_consumer(name)
|
|
146
146
|
if updater
|
|
147
147
|
updater.consume(selector, document, options)
|
|
148
148
|
else
|
|
149
149
|
master(options).update(selector, document, options)
|
|
150
150
|
end
|
|
151
151
|
end
|
|
152
|
+
|
|
153
|
+
def drop(*args)
|
|
154
|
+
@master = nil if master.drop
|
|
155
|
+
end
|
|
152
156
|
end
|
|
153
157
|
end
|
|
@@ -32,6 +32,7 @@ module Mongoid #:nodoc:
|
|
|
32
32
|
retry
|
|
33
33
|
rescue Mongo::OperationFailure => ex
|
|
34
34
|
if ex.message =~ /not master/
|
|
35
|
+
Mongoid.reconnect!
|
|
35
36
|
retries = increase_retry_attempts(retries, ex)
|
|
36
37
|
retry
|
|
37
38
|
else
|
|
@@ -51,7 +52,7 @@ module Mongoid #:nodoc:
|
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
def log_retry(retry_number, ex)
|
|
54
|
-
Mongoid.logger.warn "A #{ex.class.name} was raised. Retry attempt ##{retry_number}."
|
|
55
|
+
Mongoid.logger.warn "A #{ex.class.name} was raised. Retry attempt ##{retry_number}." if Mongoid.logger
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
end
|
data/lib/mongoid/components.rb
CHANGED
|
@@ -22,7 +22,6 @@ module Mongoid #:nodoc
|
|
|
22
22
|
include Mongoid::Dirty
|
|
23
23
|
include Mongoid::Attributes
|
|
24
24
|
include Mongoid::Collections
|
|
25
|
-
include Mongoid::Copyable
|
|
26
25
|
include Mongoid::DefaultScope
|
|
27
26
|
include Mongoid::Extras
|
|
28
27
|
include Mongoid::Fields
|
|
@@ -45,6 +44,7 @@ module Mongoid #:nodoc
|
|
|
45
44
|
include Mongoid::Timestamps::Timeless
|
|
46
45
|
include Mongoid::Validations
|
|
47
46
|
include Mongoid::Callbacks
|
|
47
|
+
include Mongoid::Copyable
|
|
48
48
|
include Mongoid::MultiDatabase
|
|
49
49
|
|
|
50
50
|
MODULES = [
|
|
@@ -66,6 +66,7 @@ module Mongoid #:nodoc
|
|
|
66
66
|
Mongoid::NestedAttributes,
|
|
67
67
|
Mongoid::Persistence,
|
|
68
68
|
Mongoid::Relations,
|
|
69
|
+
Mongoid::Relations::Proxy,
|
|
69
70
|
Mongoid::Safety,
|
|
70
71
|
Mongoid::Serialization,
|
|
71
72
|
Mongoid::Sharding,
|
|
@@ -6,9 +6,6 @@ module Mongoid #:nodoc:
|
|
|
6
6
|
# database from options.
|
|
7
7
|
class Database < Hash
|
|
8
8
|
|
|
9
|
-
# keys to remove from self to not pass through to Mongo::Connection
|
|
10
|
-
PRIVATE_OPTIONS = %w(uri database username password logger)
|
|
11
|
-
|
|
12
9
|
# Configure the database connections. This will return an array
|
|
13
10
|
# containing the master and an array of slaves.
|
|
14
11
|
#
|
|
@@ -86,7 +83,7 @@ module Mongoid #:nodoc:
|
|
|
86
83
|
#
|
|
87
84
|
# @since 2.0.0.rc.1
|
|
88
85
|
def master
|
|
89
|
-
Mongo::Connection.from_uri(uri(self), optional).tap do |conn|
|
|
86
|
+
Mongo::Connection.from_uri(uri(self), optional.symbolize_keys).tap do |conn|
|
|
90
87
|
conn.apply_saved_authentication
|
|
91
88
|
end
|
|
92
89
|
end
|
|
@@ -102,7 +99,7 @@ module Mongoid #:nodoc:
|
|
|
102
99
|
# @since 2.0.0.rc.1
|
|
103
100
|
def slaves
|
|
104
101
|
(self["slaves"] || []).map do |options|
|
|
105
|
-
Mongo::Connection.from_uri(uri(options), optional(true)).tap do |conn|
|
|
102
|
+
Mongo::Connection.from_uri(uri(options), optional(true).symbolize_keys).tap do |conn|
|
|
106
103
|
conn.apply_saved_authentication
|
|
107
104
|
end
|
|
108
105
|
end
|
|
@@ -162,8 +159,8 @@ module Mongoid #:nodoc:
|
|
|
162
159
|
:pool_size => pool_size,
|
|
163
160
|
:logger => logger? ? Mongoid::Logger.new : nil,
|
|
164
161
|
:slave_ok => slave
|
|
165
|
-
}).merge(self).reject { |k,v|
|
|
166
|
-
inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo}
|
|
162
|
+
}).merge(self).reject { |k,v| Config.blacklisted_options.include? k }.
|
|
163
|
+
inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo}
|
|
167
164
|
end
|
|
168
165
|
|
|
169
166
|
# Get a Mongo compliant URI for the database connection.
|
|
@@ -8,18 +8,20 @@ module Mongoid #:nodoc
|
|
|
8
8
|
|
|
9
9
|
# Get the name of the environment that we are running under. This first
|
|
10
10
|
# looks for Rails, then Sinatra, then a RACK_ENV environment variable,
|
|
11
|
-
# and if none of those are found
|
|
11
|
+
# and if none of those are found raises an error.
|
|
12
12
|
#
|
|
13
13
|
# @example Get the env name.
|
|
14
14
|
# Environment.env_name
|
|
15
15
|
#
|
|
16
|
+
# @raise [ Errors::NoEnvironment ] If no environment was set.
|
|
17
|
+
#
|
|
16
18
|
# @return [ String ] The name of the current environment.
|
|
17
19
|
#
|
|
18
20
|
# @since 2.3.0
|
|
19
21
|
def env_name
|
|
20
22
|
return Rails.env if defined?(Rails)
|
|
21
23
|
return Sinatra::Base.environment.to_s if defined?(Sinatra)
|
|
22
|
-
ENV["RACK_ENV"] || raise(Errors::NoEnvironment.new)
|
|
24
|
+
ENV["RACK_ENV"] || ENV["MONGOID_ENV"] || raise(Errors::NoEnvironment.new)
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
# Load the yaml from the provided path and return the settings for the
|
|
@@ -17,11 +17,9 @@ module Mongoid #:nodoc:
|
|
|
17
17
|
# yes, construction is weird but the driver wants
|
|
18
18
|
# "A list of host-port pairs ending with a hash containing any options"
|
|
19
19
|
# mongo likes symbols
|
|
20
|
-
options =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
end
|
|
24
|
-
connection = Mongo::ReplSetConnection.new(*(hosts.clone << options))
|
|
20
|
+
options = reject{ |key, value| Config.blacklisted_options.include?(key.to_s) }
|
|
21
|
+
options["logger"] = Mongoid::Logger.new
|
|
22
|
+
connection = Mongo::ReplSetConnection.new(*(hosts.clone << options.symbolize_keys))
|
|
25
23
|
|
|
26
24
|
if authenticating?
|
|
27
25
|
connection.add_auth(database, username, password)
|
data/lib/mongoid/config.rb
CHANGED
|
@@ -23,6 +23,7 @@ module Mongoid #:nodoc
|
|
|
23
23
|
option :autocreate_indexes, :default => false
|
|
24
24
|
option :identity_map_enabled, :default => false
|
|
25
25
|
option :include_root_in_json, :default => false
|
|
26
|
+
option :include_type_for_serialization, :default => false
|
|
26
27
|
option :max_retries_on_connection_failure, :default => 0
|
|
27
28
|
option :parameterize_keys, :default => true
|
|
28
29
|
option :scope_overwrite_exception, :default => false
|
|
@@ -52,6 +53,23 @@ module Mongoid #:nodoc
|
|
|
52
53
|
end
|
|
53
54
|
end
|
|
54
55
|
|
|
56
|
+
# keys to remove from self to not pass through to Mongo::Connection
|
|
57
|
+
PRIVATE_OPTIONS =
|
|
58
|
+
%w(uri host hosts port database databases username
|
|
59
|
+
password logger use_activesupport_time_zone)
|
|
60
|
+
|
|
61
|
+
# Get the blacklisted options from passing through to the driver.
|
|
62
|
+
#
|
|
63
|
+
# @example Get the blacklisted options.
|
|
64
|
+
# Config.blacklisted_options
|
|
65
|
+
#
|
|
66
|
+
# @return [ Array<String> ] The blacklist.
|
|
67
|
+
#
|
|
68
|
+
# @since 2.4.7
|
|
69
|
+
def blacklisted_options
|
|
70
|
+
PRIVATE_OPTIONS + settings.keys.map(&:to_s)
|
|
71
|
+
end
|
|
72
|
+
|
|
55
73
|
# Get any extra databases that have been configured.
|
|
56
74
|
#
|
|
57
75
|
# @example Get the extras.
|
|
@@ -210,6 +210,18 @@ module Mongoid #:nodoc:
|
|
|
210
210
|
|
|
211
211
|
protected
|
|
212
212
|
|
|
213
|
+
# Get the root class collection name.
|
|
214
|
+
#
|
|
215
|
+
# @example Get the root class collection name.
|
|
216
|
+
# context.collection_name
|
|
217
|
+
#
|
|
218
|
+
# @return [ String ] The name of the collection.
|
|
219
|
+
#
|
|
220
|
+
# @since 2.4.3
|
|
221
|
+
def collection_name
|
|
222
|
+
root ? root.collection_name : nil
|
|
223
|
+
end
|
|
224
|
+
|
|
213
225
|
# Filters the documents against the criteria's selector
|
|
214
226
|
#
|
|
215
227
|
# @example Filter the documents.
|
|
@@ -251,10 +263,22 @@ module Mongoid #:nodoc:
|
|
|
251
263
|
documents
|
|
252
264
|
end
|
|
253
265
|
|
|
266
|
+
# Get the root document for the enumerable.
|
|
267
|
+
#
|
|
268
|
+
# @example Get the root document.
|
|
269
|
+
# context.root
|
|
270
|
+
#
|
|
271
|
+
# @return [ Document ] The root.
|
|
254
272
|
def root
|
|
255
273
|
@root ||= documents.first.try(:_root)
|
|
256
274
|
end
|
|
257
275
|
|
|
276
|
+
# Get the root class for the enumerable.
|
|
277
|
+
#
|
|
278
|
+
# @example Get the root class.
|
|
279
|
+
# context.root_class
|
|
280
|
+
#
|
|
281
|
+
# @return [ Class ] The root class.
|
|
258
282
|
def root_class
|
|
259
283
|
@root_class ||= root ? root.class : nil
|
|
260
284
|
end
|
|
@@ -279,7 +303,8 @@ module Mongoid #:nodoc:
|
|
|
279
303
|
return documents if options[:sort].blank?
|
|
280
304
|
documents.sort_by do |document|
|
|
281
305
|
options[:sort].map do |key, direction|
|
|
282
|
-
|
|
306
|
+
key = key.to_s.gsub(/(.*)\.#{I18n.locale}$/, '\1')
|
|
307
|
+
Sort.new(document.send(key), direction)
|
|
283
308
|
end
|
|
284
309
|
end
|
|
285
310
|
end
|
|
@@ -135,6 +135,28 @@ module Mongoid #:nodoc:
|
|
|
135
135
|
klass.collection.distinct(field, selector)
|
|
136
136
|
end
|
|
137
137
|
|
|
138
|
+
# Eager load the inclusions for the provided documents.
|
|
139
|
+
#
|
|
140
|
+
# @example Eager load the inclusions.
|
|
141
|
+
# context.eager_load(docs)
|
|
142
|
+
#
|
|
143
|
+
# @param [ Array<Document> ] docs The docs returning from the db.
|
|
144
|
+
#
|
|
145
|
+
# @since 2.4.1
|
|
146
|
+
def eager_load(docs)
|
|
147
|
+
criteria.inclusions.reject! do |metadata|
|
|
148
|
+
unless docs.empty?
|
|
149
|
+
parent_ids = docs.map(&:id)
|
|
150
|
+
if metadata.macro == :referenced_in
|
|
151
|
+
child_ids = load_ids(metadata.foreign_key)
|
|
152
|
+
metadata.eager_load(child_ids)
|
|
153
|
+
else
|
|
154
|
+
metadata.eager_load(parent_ids)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
138
160
|
# Execute the context. This will take the selector and options
|
|
139
161
|
# and pass them on to the Ruby driver's +find()+ method on the collection. The
|
|
140
162
|
# collection itself will be retrieved from the class provided, and once the
|
|
@@ -148,15 +170,7 @@ module Mongoid #:nodoc:
|
|
|
148
170
|
collection, options = klass.collection, process_options
|
|
149
171
|
if criteria.inclusions.any?
|
|
150
172
|
collection.find(selector, options).entries.tap do |docs|
|
|
151
|
-
|
|
152
|
-
criteria.inclusions.reject! do |metadata|
|
|
153
|
-
if metadata.macro == :referenced_in
|
|
154
|
-
child_ids = load_ids(metadata.foreign_key)
|
|
155
|
-
metadata.eager_load(child_ids)
|
|
156
|
-
else
|
|
157
|
-
metadata.eager_load(parent_ids)
|
|
158
|
-
end
|
|
159
|
-
end
|
|
173
|
+
eager_load(docs)
|
|
160
174
|
end
|
|
161
175
|
else
|
|
162
176
|
collection.find(selector, options)
|
|
@@ -189,7 +203,12 @@ module Mongoid #:nodoc:
|
|
|
189
203
|
# @return [ Document ] The first document in the collection.
|
|
190
204
|
def first
|
|
191
205
|
attributes = klass.collection.find_one(selector, options_with_default_sorting)
|
|
192
|
-
|
|
206
|
+
return nil unless attributes
|
|
207
|
+
selecting do
|
|
208
|
+
Mongoid::Factory.from_db(klass, attributes).tap do |doc|
|
|
209
|
+
eager_load([ doc ]) if criteria.inclusions.any?
|
|
210
|
+
end
|
|
211
|
+
end
|
|
193
212
|
end
|
|
194
213
|
alias :one :first
|
|
195
214
|
|
|
@@ -237,9 +256,11 @@ module Mongoid #:nodoc:
|
|
|
237
256
|
# @example Iterate over the results.
|
|
238
257
|
# context.iterate { |doc| p doc }
|
|
239
258
|
def iterate(&block)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
259
|
+
selecting do
|
|
260
|
+
return caching(&block) if cached?
|
|
261
|
+
if block_given?
|
|
262
|
+
execute.each { |doc| yield doc }
|
|
263
|
+
end
|
|
243
264
|
end
|
|
244
265
|
end
|
|
245
266
|
|
|
@@ -255,7 +276,12 @@ module Mongoid #:nodoc:
|
|
|
255
276
|
opts = options_with_default_sorting
|
|
256
277
|
opts[:sort] = opts[:sort].map{ |option| [ option[0], option[1].invert ] }.uniq
|
|
257
278
|
attributes = klass.collection.find_one(selector, opts)
|
|
258
|
-
|
|
279
|
+
return nil unless attributes
|
|
280
|
+
selecting do
|
|
281
|
+
Mongoid::Factory.from_db(klass, attributes).tap do |doc|
|
|
282
|
+
eager_load([ doc ]) if criteria.inclusions.any?
|
|
283
|
+
end
|
|
284
|
+
end
|
|
259
285
|
end
|
|
260
286
|
|
|
261
287
|
# Return the max value for a field.
|
|
@@ -434,6 +460,28 @@ module Mongoid #:nodoc:
|
|
|
434
460
|
end
|
|
435
461
|
options.dup
|
|
436
462
|
end
|
|
463
|
+
|
|
464
|
+
# If we are limiting results, we need to set the field limitations on a
|
|
465
|
+
# thread local to avoid overriding the default values.
|
|
466
|
+
#
|
|
467
|
+
# @example Execute with selection.
|
|
468
|
+
# context.selecting do
|
|
469
|
+
# collection.find
|
|
470
|
+
# end
|
|
471
|
+
#
|
|
472
|
+
# @return [ Object ] The yielded value.
|
|
473
|
+
#
|
|
474
|
+
# @since 2.4.4
|
|
475
|
+
def selecting
|
|
476
|
+
begin
|
|
477
|
+
unless options[:fields].blank?
|
|
478
|
+
Threaded.selection = options[:fields]
|
|
479
|
+
end
|
|
480
|
+
yield
|
|
481
|
+
ensure
|
|
482
|
+
Threaded.selection = nil
|
|
483
|
+
end
|
|
484
|
+
end
|
|
437
485
|
end
|
|
438
486
|
end
|
|
439
487
|
end
|
data/lib/mongoid/copyable.rb
CHANGED
|
@@ -6,11 +6,10 @@ module Mongoid #:nodoc:
|
|
|
6
6
|
extend ActiveSupport::Concern
|
|
7
7
|
|
|
8
8
|
COPYABLES = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
:@previous_modifications
|
|
9
|
+
:attributes,
|
|
10
|
+
:metadata,
|
|
11
|
+
:changed_attributes,
|
|
12
|
+
:previous_changes
|
|
14
13
|
]
|
|
15
14
|
|
|
16
15
|
protected
|
|
@@ -24,18 +23,49 @@ module Mongoid #:nodoc:
|
|
|
24
23
|
# @example Clone the document.
|
|
25
24
|
# document.clone
|
|
26
25
|
#
|
|
26
|
+
# @param [ Document ] other The document getting cloned.
|
|
27
|
+
#
|
|
28
|
+
# @return [ Document ] The new document.
|
|
29
|
+
def initialize_copy(other)
|
|
30
|
+
__copy__(other)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Clone or dup the current +Document+. This will return all attributes with
|
|
34
|
+
# the exception of the document's id and versions, and will reset all the
|
|
35
|
+
# instance variables.
|
|
36
|
+
#
|
|
37
|
+
# This clone also includes embedded documents.
|
|
38
|
+
#
|
|
27
39
|
# @example Dup the document.
|
|
28
40
|
# document.dup
|
|
29
41
|
#
|
|
30
42
|
# @param [ Document ] other The document getting cloned.
|
|
31
43
|
#
|
|
32
44
|
# @return [ Document ] The new document.
|
|
33
|
-
def
|
|
45
|
+
def initialize_dup(other)
|
|
46
|
+
__copy__(other)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
# Handle the copy of the object.
|
|
52
|
+
#
|
|
53
|
+
# @api private
|
|
54
|
+
#
|
|
55
|
+
# @example Copy the object.
|
|
56
|
+
# document.__copy__(other)
|
|
57
|
+
#
|
|
58
|
+
# @param [ Document ] other The other document.
|
|
59
|
+
#
|
|
60
|
+
# @return [ Document ] self.
|
|
61
|
+
#
|
|
62
|
+
# @since 3.0.0
|
|
63
|
+
def __copy__(other)
|
|
34
64
|
other.as_document
|
|
35
65
|
instance_variables.each { |name| remove_instance_variable(name) }
|
|
36
66
|
COPYABLES.each do |name|
|
|
37
|
-
value = other.
|
|
38
|
-
instance_variable_set(name, value ? value.dup : nil)
|
|
67
|
+
value = other.send(name)
|
|
68
|
+
instance_variable_set(:"@#{name}", value ? value.dup : nil)
|
|
39
69
|
end
|
|
40
70
|
attributes.delete("_id")
|
|
41
71
|
if attributes.delete("versions")
|
data/lib/mongoid/criteria.rb
CHANGED
|
@@ -262,6 +262,7 @@ module Mongoid #:nodoc:
|
|
|
262
262
|
scope_options = @options.dup
|
|
263
263
|
sorting = scope_options.delete(:sort)
|
|
264
264
|
scope_options[:order_by] = sorting if sorting
|
|
265
|
+
scope_options[:includes] = inclusions.map(&:name) if inclusions.any?
|
|
265
266
|
{ :where => @selector }.merge(scope_options)
|
|
266
267
|
end
|
|
267
268
|
alias :to_ary :to_a
|
|
@@ -96,7 +96,9 @@ module Mongoid #:nodoc:
|
|
|
96
96
|
def without(*args)
|
|
97
97
|
clone.tap do |crit|
|
|
98
98
|
if args.any?
|
|
99
|
-
|
|
99
|
+
unless args == [ :id ] || args == [ :_id ]
|
|
100
|
+
crit.options[:fields] = {}
|
|
101
|
+
end
|
|
100
102
|
args.flatten.each do |f|
|
|
101
103
|
crit.options[:fields][f] = 0
|
|
102
104
|
end
|
|
@@ -210,7 +210,7 @@ module Mongoid #:nodoc:
|
|
|
210
210
|
#
|
|
211
211
|
# @since 2.2.0
|
|
212
212
|
def includes(*relations)
|
|
213
|
-
relations.each do |name|
|
|
213
|
+
relations.flatten.each do |name|
|
|
214
214
|
inclusions.push(klass.reflect_on_association(name))
|
|
215
215
|
end
|
|
216
216
|
clone
|
|
@@ -268,7 +268,7 @@ module Mongoid #:nodoc:
|
|
|
268
268
|
if key.mongoid_id?
|
|
269
269
|
if crit.selector.has_key?("$and")
|
|
270
270
|
crit.selector["$and"] << { key => value }
|
|
271
|
-
|
|
271
|
+
elsif crit.selector[key] != value
|
|
272
272
|
crit.selector["$and"] = [{ key => crit.selector.delete(key) }, { key => value }]
|
|
273
273
|
end
|
|
274
274
|
elsif crit.selector[key].respond_to?(:merge) && value.respond_to?(:merge)
|
|
@@ -109,7 +109,7 @@ module Mongoid #:nodoc:
|
|
|
109
109
|
#
|
|
110
110
|
# @return [ Criteria ] The cloned criteria.
|
|
111
111
|
def limit(value = 20)
|
|
112
|
-
clone.tap { |crit| crit.options[:limit] = value }
|
|
112
|
+
clone.tap { |crit| crit.options[:limit] = value.to_i }
|
|
113
113
|
end
|
|
114
114
|
|
|
115
115
|
# Returns the offset option. If a per_page option is in the list then it
|
|
@@ -163,7 +163,7 @@ module Mongoid #:nodoc:
|
|
|
163
163
|
#
|
|
164
164
|
# @return [ Criteria ] The cloned criteria.
|
|
165
165
|
def skip(value = 0)
|
|
166
|
-
clone.tap { |crit| crit.options[:skip] = value }
|
|
166
|
+
clone.tap { |crit| crit.options[:skip] = value.to_i }
|
|
167
167
|
end
|
|
168
168
|
|
|
169
169
|
# Adds a criterion to the +Criteria+ that specifies a type or an Array of
|
|
@@ -85,11 +85,32 @@ module Mongoid #:nodoc:
|
|
|
85
85
|
# @since 1.0.0
|
|
86
86
|
def try_to_typecast(key, value)
|
|
87
87
|
access = key.to_s
|
|
88
|
-
if
|
|
89
|
-
|
|
88
|
+
if field = fields[key.to_s] || fields[aliased_fields[key.to_s]]
|
|
89
|
+
typecast_value_for(field, value)
|
|
90
|
+
elsif proper_and_or_value?(key, value)
|
|
91
|
+
handle_and_or_value(value)
|
|
92
|
+
else
|
|
93
|
+
value
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def proper_and_or_value?(key, value)
|
|
98
|
+
["$and", "$or"].include?(key) &&
|
|
99
|
+
value.is_a?(Array) &&
|
|
100
|
+
value.all?{ |e| e.is_a?(Hash) }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def handle_and_or_value(values)
|
|
104
|
+
[].tap do |result|
|
|
105
|
+
result.push(*values.map do |value|
|
|
106
|
+
Hash[value.map do |_key, _value|
|
|
107
|
+
if klass.fields[_key.to_s].try(:localized?)
|
|
108
|
+
_key = "#{_key}.#{::I18n.locale}"
|
|
109
|
+
end
|
|
110
|
+
[_key, try_to_typecast(_key, _value)]
|
|
111
|
+
end]
|
|
112
|
+
end)
|
|
90
113
|
end
|
|
91
|
-
field = fields[access] || fields[aliased_fields[access]]
|
|
92
|
-
typecast_value_for(field, value)
|
|
93
114
|
end
|
|
94
115
|
|
|
95
116
|
# Get the typecast value for the defined field.
|
data/lib/mongoid/cursor.rb
CHANGED
|
@@ -45,8 +45,10 @@ module Mongoid #:nodoc
|
|
|
45
45
|
# @example Iterate over the cursor.
|
|
46
46
|
# cursor.each { |doc| p doc.title }
|
|
47
47
|
def each
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
retry_on_connection_failure do
|
|
49
|
+
while document = cursor.next_document
|
|
50
|
+
yield Factory.from_db(klass, document)
|
|
51
|
+
end
|
|
50
52
|
end
|
|
51
53
|
end
|
|
52
54
|
|
data/lib/mongoid/dirty.rb
CHANGED
|
@@ -24,7 +24,21 @@ module Mongoid #:nodoc:
|
|
|
24
24
|
#
|
|
25
25
|
# @since 2.4.0
|
|
26
26
|
def changed?
|
|
27
|
-
changed_attributes.any?
|
|
27
|
+
changed_attributes.any? || children_changed?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Have any children (embedded documents) of this document changed?
|
|
31
|
+
#
|
|
32
|
+
# @example Have any children changed?
|
|
33
|
+
# model.children_changed?
|
|
34
|
+
#
|
|
35
|
+
# @return [ true, false ] If any children have changed.
|
|
36
|
+
#
|
|
37
|
+
# @since 2.4.1
|
|
38
|
+
def children_changed?
|
|
39
|
+
_children.any? do |child|
|
|
40
|
+
child.changed?
|
|
41
|
+
end
|
|
28
42
|
end
|
|
29
43
|
|
|
30
44
|
# Get the attribute changes.
|
|
@@ -117,8 +131,14 @@ module Mongoid #:nodoc:
|
|
|
117
131
|
field = fields[name]
|
|
118
132
|
key = embedded? ? "#{atomic_position}.#{name}" : name
|
|
119
133
|
if field && field.resizable?
|
|
120
|
-
|
|
121
|
-
|
|
134
|
+
field.add_atomic_changes(
|
|
135
|
+
self,
|
|
136
|
+
name,
|
|
137
|
+
key,
|
|
138
|
+
modifications,
|
|
139
|
+
new,
|
|
140
|
+
old
|
|
141
|
+
)
|
|
122
142
|
else
|
|
123
143
|
modifications[key] = new
|
|
124
144
|
end
|
|
@@ -207,36 +227,59 @@ module Mongoid #:nodoc:
|
|
|
207
227
|
# Generate all the dirty methods needed for the attribute.
|
|
208
228
|
#
|
|
209
229
|
# @example Generate the dirty methods.
|
|
210
|
-
# Model.create_dirty_methods("name")
|
|
230
|
+
# Model.create_dirty_methods("name", "name")
|
|
211
231
|
#
|
|
212
|
-
# @param [ String ] name The name of the
|
|
232
|
+
# @param [ String ] name The name of the field.
|
|
233
|
+
# @param [ String ] name The name of the accessor.
|
|
213
234
|
#
|
|
214
235
|
# @return [ Module ] The fields module.
|
|
215
236
|
#
|
|
216
237
|
# @since 2.4.0
|
|
217
|
-
def create_dirty_methods(name)
|
|
238
|
+
def create_dirty_methods(name, meth)
|
|
218
239
|
generated_methods.module_eval do
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
attribute_change(
|
|
240
|
+
if meth =~ /\W/
|
|
241
|
+
define_method("#{meth}_change") do
|
|
242
|
+
attribute_change(name)
|
|
222
243
|
end
|
|
223
244
|
|
|
224
|
-
|
|
225
|
-
attribute_changed?(
|
|
245
|
+
define_method("#{meth}_changed?") do
|
|
246
|
+
attribute_changed?(name)
|
|
226
247
|
end
|
|
227
248
|
|
|
228
|
-
|
|
229
|
-
attribute_was(
|
|
249
|
+
define_method("#{meth}_was") do
|
|
250
|
+
attribute_was(name)
|
|
230
251
|
end
|
|
231
252
|
|
|
232
|
-
|
|
233
|
-
attribute_will_change!(
|
|
253
|
+
define_method("#{meth}_will_change!") do
|
|
254
|
+
attribute_will_change!(name)
|
|
234
255
|
end
|
|
235
256
|
|
|
236
|
-
|
|
237
|
-
reset_attribute!(
|
|
257
|
+
define_method("reset_#{meth}!") do
|
|
258
|
+
reset_attribute!(name)
|
|
238
259
|
end
|
|
239
|
-
|
|
260
|
+
else
|
|
261
|
+
class_eval <<-EOM
|
|
262
|
+
def #{meth}_change
|
|
263
|
+
attribute_change(#{name.inspect})
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def #{meth}_changed?
|
|
267
|
+
attribute_changed?(#{name.inspect})
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def #{meth}_was
|
|
271
|
+
attribute_was(#{name.inspect})
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def #{meth}_will_change!
|
|
275
|
+
attribute_will_change!(#{name.inspect})
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def reset_#{meth}!
|
|
279
|
+
reset_attribute!(#{name.inspect})
|
|
280
|
+
end
|
|
281
|
+
EOM
|
|
282
|
+
end
|
|
240
283
|
end
|
|
241
284
|
end
|
|
242
285
|
end
|
data/lib/mongoid/document.rb
CHANGED
|
@@ -44,7 +44,11 @@ module Mongoid #:nodoc:
|
|
|
44
44
|
#
|
|
45
45
|
# @return [ true, false ] True if the classes are equal, false if not.
|
|
46
46
|
def ===(other)
|
|
47
|
-
other.
|
|
47
|
+
if other.class == Class
|
|
48
|
+
self.class === other
|
|
49
|
+
else
|
|
50
|
+
id == other.id
|
|
51
|
+
end
|
|
48
52
|
end
|
|
49
53
|
|
|
50
54
|
# Delegates to ==. Used when needing checks in hashes.
|
|
@@ -276,7 +280,7 @@ module Mongoid #:nodoc:
|
|
|
276
280
|
#
|
|
277
281
|
# @since 2.0.0.rc.4
|
|
278
282
|
def ===(other)
|
|
279
|
-
|
|
283
|
+
other.class == Class ? self <= other : other.is_a?(self)
|
|
280
284
|
end
|
|
281
285
|
|
|
282
286
|
# Instantiate a new object, only when loaded from the database or when
|