mongoid 2.3.0 → 2.3.1

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.
Files changed (56) hide show
  1. data/CHANGELOG.md +56 -2
  2. data/lib/config/locales/bg.yml +2 -0
  3. data/lib/config/locales/de.yml +2 -0
  4. data/lib/config/locales/en-GB.yml +2 -0
  5. data/lib/config/locales/en.yml +2 -0
  6. data/lib/config/locales/es.yml +2 -0
  7. data/lib/config/locales/fr.yml +2 -0
  8. data/lib/config/locales/hi.yml +2 -0
  9. data/lib/config/locales/hu.yml +2 -0
  10. data/lib/config/locales/id.yml +2 -0
  11. data/lib/config/locales/it.yml +2 -0
  12. data/lib/config/locales/ja.yml +2 -0
  13. data/lib/config/locales/kr.yml +2 -0
  14. data/lib/config/locales/nl.yml +2 -0
  15. data/lib/config/locales/pl.yml +2 -0
  16. data/lib/config/locales/pt-BR.yml +2 -0
  17. data/lib/config/locales/pt.yml +2 -0
  18. data/lib/config/locales/ro.yml +2 -0
  19. data/lib/config/locales/ru.yml +2 -0
  20. data/lib/config/locales/sv.yml +2 -0
  21. data/lib/config/locales/vi.yml +2 -0
  22. data/lib/config/locales/zh-CN.yml +2 -0
  23. data/lib/mongoid/contexts/mongo.rb +1 -1
  24. data/lib/mongoid/criterion/inclusion.rb +39 -40
  25. data/lib/mongoid/criterion/selector.rb +5 -0
  26. data/lib/mongoid/dirty.rb +4 -26
  27. data/lib/mongoid/errors.rb +1 -0
  28. data/lib/mongoid/errors/invalid_time.rb +25 -0
  29. data/lib/mongoid/extensions.rb +2 -0
  30. data/lib/mongoid/extensions/hash/criteria_helpers.rb +1 -2
  31. data/lib/mongoid/extensions/object_id/conversions.rb +2 -4
  32. data/lib/mongoid/extensions/string/checks.rb +12 -0
  33. data/lib/mongoid/extensions/symbol/checks.rb +23 -0
  34. data/lib/mongoid/extras.rb +0 -22
  35. data/lib/mongoid/fields.rb +1 -1
  36. data/lib/mongoid/fields/serializable.rb +14 -7
  37. data/lib/mongoid/fields/serializable/timekeeping.rb +6 -2
  38. data/lib/mongoid/named_scope.rb +7 -3
  39. data/lib/mongoid/nested_attributes.rb +0 -12
  40. data/lib/mongoid/paranoia.rb +62 -8
  41. data/lib/mongoid/railties/database.rake +6 -3
  42. data/lib/mongoid/relations.rb +15 -0
  43. data/lib/mongoid/relations/bindings/referenced/in.rb +1 -1
  44. data/lib/mongoid/relations/builders/referenced/in.rb +1 -1
  45. data/lib/mongoid/relations/builders/referenced/one.rb +1 -2
  46. data/lib/mongoid/relations/cascading.rb +0 -12
  47. data/lib/mongoid/relations/embedded/many.rb +28 -9
  48. data/lib/mongoid/relations/macros.rb +8 -18
  49. data/lib/mongoid/relations/metadata.rb +2 -5
  50. data/lib/mongoid/relations/polymorphic.rb +0 -25
  51. data/lib/mongoid/relations/referenced/many.rb +29 -10
  52. data/lib/mongoid/relations/referenced/many_to_many.rb +13 -3
  53. data/lib/mongoid/relations/targets/enumerable.rb +2 -3
  54. data/lib/mongoid/version.rb +1 -1
  55. data/lib/mongoid/versioning.rb +1 -13
  56. metadata +21 -19
@@ -8,6 +8,7 @@ require "mongoid/errors/invalid_database"
8
8
  require "mongoid/errors/invalid_field"
9
9
  require "mongoid/errors/invalid_find"
10
10
  require "mongoid/errors/invalid_options"
11
+ require "mongoid/errors/invalid_time"
11
12
  require "mongoid/errors/invalid_type"
12
13
  require "mongoid/errors/mixed_relations"
13
14
  require "mongoid/errors/too_many_nested_attribute_records"
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc
3
+ module Errors #:nodoc
4
+
5
+ # This exception is raised when a bad value is attempted to be converted to
6
+ # a date or time.
7
+ class InvalidTime < MongoidError
8
+
9
+ attr_reader :klass, :value
10
+
11
+ # Create the new invalid date error.
12
+ #
13
+ # @example Create the new invalid date error.
14
+ # InvalidTime.new("this is not a time")
15
+ #
16
+ # @param [ Object ] value The value that was attempted.
17
+ #
18
+ # @since 2.3.1
19
+ def initialize(value)
20
+ @value = value
21
+ super(translate("invalid_time", { :value => value }))
22
+ end
23
+ end
24
+ end
25
+ end
@@ -13,6 +13,7 @@ require "mongoid/extensions/proc/scoping"
13
13
  require "mongoid/extensions/string/checks"
14
14
  require "mongoid/extensions/string/conversions"
15
15
  require "mongoid/extensions/string/inflections"
16
+ require "mongoid/extensions/symbol/checks"
16
17
  require "mongoid/extensions/symbol/inflections"
17
18
  require "mongoid/extensions/true_class/equality"
18
19
  require "mongoid/extensions/object_id/conversions"
@@ -62,6 +63,7 @@ end
62
63
 
63
64
  class Symbol #:nodoc
64
65
  remove_method :size if instance_methods.include? :size # temporal fix for ruby 1.9
66
+ include Mongoid::Extensions::Symbol::Checks
65
67
  include Mongoid::Extensions::Symbol::Inflections
66
68
  end
67
69
 
@@ -17,8 +17,7 @@ module Mongoid #:nodoc:
17
17
  def expand_complex_criteria
18
18
  {}.tap do |hsh|
19
19
  each_pair do |k,v|
20
- case k
21
- when Mongoid::Criterion::Complex
20
+ if k.respond_to?(:key) && k.respond_to?(:to_mongo_query)
22
21
  hsh[k.key] ||= {}
23
22
  hsh[k.key].merge!(k.to_mongo_query(v))
24
23
  else
@@ -38,7 +38,7 @@ module Mongoid #:nodoc:
38
38
  if args.unconvertable_to_bson?
39
39
  args
40
40
  else
41
- BSON::ObjectId.from_string(args)
41
+ BSON::ObjectId.legal?(args) ? BSON::ObjectId.from_string(args) : args
42
42
  end
43
43
  when ::Array
44
44
  args.delete_if { |arg| arg.blank? } if reject_blank
@@ -47,9 +47,7 @@ module Mongoid #:nodoc:
47
47
  args.tap do |hash|
48
48
  hash.each_pair do |key, value|
49
49
  next unless klass.object_id_field?(key)
50
- begin
51
- hash[key] = convert(klass, value, reject_blank)
52
- rescue BSON::InvalidObjectId; end
50
+ hash[key] = convert(klass, value, reject_blank)
53
51
  end
54
52
  end
55
53
  else
@@ -7,6 +7,18 @@ module Mongoid #:nodoc:
7
7
  module Checks #:nodoc:
8
8
  attr_accessor :unconvertable_to_bson
9
9
 
10
+ # Is the string a valid value for a Mongoid id?
11
+ #
12
+ # @example Is the string an id value?
13
+ # "_id".mongoid_id?
14
+ #
15
+ # @return [ true, false ] If the string is id or _id.
16
+ #
17
+ # @since 2.3.1
18
+ def mongoid_id?
19
+ self =~ /^(|_)id$/
20
+ end
21
+
10
22
  # Is the object not to be converted to bson on criteria creation?
11
23
  #
12
24
  # @example Is the object unconvertable?
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Symbol #:nodoc:
5
+
6
+ # This module has object checks in it.
7
+ module Checks #:nodoc:
8
+
9
+ # Is the symbol a valid value for a Mongoid id?
10
+ #
11
+ # @example Is the string an id value?
12
+ # :_id.mongoid_id?
13
+ #
14
+ # @return [ true, false ] If the symbol is :id or :_id.
15
+ #
16
+ # @since 2.3.1
17
+ def mongoid_id?
18
+ to_s =~ /^(|_)id$/
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -10,18 +10,6 @@ module Mongoid #:nodoc:
10
10
  self.cached = false
11
11
  end
12
12
 
13
- # Is the class cached?
14
- #
15
- # @note Refactored from using delegate for class load performance.
16
- #
17
- # @example Is the class cached?
18
- # person.cached?
19
- #
20
- # @return [ true, false ] If the class is cached.
21
- def cached?
22
- self.class.cached?
23
- end
24
-
25
13
  module ClassMethods #:nodoc
26
14
 
27
15
  # Sets caching on for this class. This class level configuration will
@@ -38,16 +26,6 @@ module Mongoid #:nodoc:
38
26
  def cache
39
27
  self.cached = true
40
28
  end
41
-
42
- # Determines if the class is cached or not.
43
- #
44
- # @example Are class reads cached?
45
- # Document.cached?
46
- #
47
- # @return [ true, false ] If the reads are cached.
48
- def cached?
49
- !!self.cached
50
- end
51
29
  end
52
30
  end
53
31
  end
@@ -231,7 +231,7 @@ module Mongoid #:nodoc
231
231
  type = options[:localize] ? Fields::Serializable::Localized : options[:type]
232
232
  Mappings.for(type, options[:identity]).instantiate(name, options).tap do |field|
233
233
  fields[name] = field
234
- defaults << name unless field.default.nil?
234
+ defaults << name unless field.default_val.nil?
235
235
  create_accessors(name, meth, options)
236
236
  process_options(field)
237
237
  define_attribute_method(name)
@@ -25,8 +25,15 @@ module Mongoid #:nodoc:
25
25
  module Serializable
26
26
  extend ActiveSupport::Concern
27
27
 
28
+ included do
29
+ # @todo: Durran: Pull out in 3.0.0
30
+ unless method_defined?(:default)
31
+ alias :default :default_val
32
+ end
33
+ end
34
+
28
35
  # Set readers for the instance variables.
29
- attr_accessor :default, :label, :localize, :name, :options
36
+ attr_accessor :default_val, :label, :localize, :name, :options
30
37
 
31
38
  # When reading the field do we need to cast the value? This holds true when
32
39
  # times are stored or for big decimals which are stored as strings.
@@ -82,10 +89,10 @@ module Mongoid #:nodoc:
82
89
  #
83
90
  # @since 2.1.8
84
91
  def eval_default(doc)
85
- if default.respond_to?(:call)
86
- serialize(doc.instance_exec(&default))
92
+ if default_val.respond_to?(:call)
93
+ serialize(doc.instance_exec(&default_val))
87
94
  else
88
- serialize(default.duplicable? ? default.dup : default)
95
+ serialize(default_val.duplicable? ? default_val.dup : default_val)
89
96
  end
90
97
  end
91
98
 
@@ -182,9 +189,9 @@ module Mongoid #:nodoc:
182
189
  field.options = options
183
190
  field.label = options[:label]
184
191
  field.localize = options[:localize]
185
- field.default = options[:default]
186
- unless field.default
187
- field.default = {} if field.localized?
192
+ field.default_val = options[:default]
193
+ unless field.default_val
194
+ field.default_val = {} if field.localized?
188
195
  end
189
196
  end
190
197
  end
@@ -51,8 +51,12 @@ module Mongoid #:nodoc:
51
51
  # @since 2.1.0
52
52
  def serialize(object)
53
53
  return nil if object.blank?
54
- time = convert_to_time(object)
55
- strip_milliseconds(time).utc
54
+ begin
55
+ time = convert_to_time(object)
56
+ strip_milliseconds(time).utc
57
+ rescue ArgumentError
58
+ raise Errors::InvalidTime.new(object)
59
+ end
56
60
  end
57
61
 
58
62
  # Convert the provided object to a UTC time to store in the database.
@@ -123,12 +123,16 @@ module Mongoid #:nodoc:
123
123
  end
124
124
  end
125
125
 
126
- protected
126
+ protected
127
127
 
128
128
  def valid_scope_name?(name)
129
129
  if !scopes[name] && respond_to?(name, true)
130
- Mongoid.logger.warn "Creating scope :#{name}. " \
131
- "Overwriting existing method #{self.name}.#{name}." if Mongoid.logger
130
+ if Mongoid.logger
131
+ Mongoid.logger.warn(
132
+ "Creating scope :#{name}. " +
133
+ "Overwriting existing method #{self.name}.#{name}."
134
+ )
135
+ end
132
136
  end
133
137
  end
134
138
  end
@@ -10,18 +10,6 @@ module Mongoid #:nodoc:
10
10
  self.nested_attributes = []
11
11
  end
12
12
 
13
- # Get the nested attributes.
14
- #
15
- # @note Refactored from using delegate for class load performance.
16
- #
17
- # @example Get the nested attributes.
18
- # model.nested_attributes
19
- #
20
- # @return [ Array<String> ] The nested attributes methods.
21
- def nested_attributes
22
- self.class.nested_attributes
23
- end
24
-
25
13
  module ClassMethods #:nodoc:
26
14
 
27
15
  REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |_, value| value.blank? } }
@@ -22,6 +22,10 @@ module Mongoid #:nodoc:
22
22
  #
23
23
  # @example Hard destroy the document.
24
24
  # document.destroy!
25
+ #
26
+ # @return [ true, false ] If the operation succeeded.
27
+ #
28
+ # @since 1.0.0
25
29
  def destroy!
26
30
  run_callbacks(:destroy) { delete! }
27
31
  end
@@ -30,8 +34,11 @@ module Mongoid #:nodoc:
30
34
  #
31
35
  # @example Hard delete the document.
32
36
  # document.delete!
37
+ #
38
+ # @return [ true, false ] If the operation succeeded.
39
+ #
40
+ # @since 1.0.0
33
41
  def delete!
34
- @destroyed = true
35
42
  Persistence::Operations.remove(self).persist
36
43
  end
37
44
 
@@ -44,10 +51,19 @@ module Mongoid #:nodoc:
44
51
  # @param [ Hash ] options The database options.
45
52
  #
46
53
  # @return [ true ] True.
54
+ #
55
+ # @since 1.0.0
47
56
  def remove(options = {})
48
- now = Time.now
49
- collection.update({ :_id => id }, { '$set' => { :deleted_at => now } })
50
- @attributes["deleted_at"] = now
57
+ time = self.deleted_at = Time.now
58
+ paranoid_collection.update(
59
+ atomic_selector,
60
+ { "$set" => { paranoid_field => time }},
61
+ Safety.merge_safety_options(options)
62
+ )
63
+ cascade!
64
+ @destroyed = true
65
+ IdentityMap.remove(self)
66
+ Threaded.clear_options!
51
67
  true
52
68
  end
53
69
  alias :delete :remove
@@ -56,9 +72,10 @@ module Mongoid #:nodoc:
56
72
  #
57
73
  # @example Is the document destroyed?
58
74
  # person.destroyed?
59
-
60
75
  #
61
76
  # @return [ true, false ] If the document is destroyed.
77
+ #
78
+ # @since 1.0.0
62
79
  def destroyed?
63
80
  @destroyed || !!deleted_at
64
81
  end
@@ -68,9 +85,42 @@ module Mongoid #:nodoc:
68
85
  #
69
86
  # @example Restore the document from deleted state.
70
87
  # document.restore
88
+ #
89
+ # @return [ Time ] The time the document had been deleted.
90
+ #
91
+ # @since 1.0.0
71
92
  def restore
72
- collection.update({ :_id => id }, { '$unset' => { :deleted_at => true } })
73
- @attributes.delete("deleted_at")
93
+ paranoid_collection.update(
94
+ atomic_selector,
95
+ { "$unset" => { paranoid_field => true }}
96
+ )
97
+ attributes.delete("deleted_at")
98
+ end
99
+
100
+ private
101
+
102
+ # Get the collection to be used for paranoid operations.
103
+ #
104
+ # @example Get the paranoid collection.
105
+ # document.paranoid_collection
106
+ #
107
+ # @return [ Collection ] The root collection.
108
+ #
109
+ # @since 2.3.1
110
+ def paranoid_collection
111
+ embedded? ? _root.collection : self.collection
112
+ end
113
+
114
+ # Get the field to be used for paranoid operations.
115
+ #
116
+ # @example Get the paranoid field.
117
+ # document.paranoid_field
118
+ #
119
+ # @return [ String ] The deleted at field.
120
+ #
121
+ # @since 2.3.1
122
+ def paranoid_field
123
+ embedded? ? "#{atomic_position}.deleted_at" : "deleted_at"
74
124
  end
75
125
 
76
126
  module ClassMethods #:nodoc:
@@ -84,8 +134,10 @@ module Mongoid #:nodoc:
84
134
  # @param [ Array ] args The arguments.
85
135
  #
86
136
  # @return [ Criteria ] The paranoid compliant criteria.
137
+ #
138
+ # @since 1.0.0
87
139
  def criteria(embedded = false, scoped = true)
88
- scoped ? super.merge({ :conditions => { :deleted_at => nil } }) : super
140
+ scoped ? super.where(:deleted_at => nil) : super
89
141
  end
90
142
 
91
143
  # Find deleted documents
@@ -96,6 +148,8 @@ module Mongoid #:nodoc:
96
148
  # Person.deleted.find("4c188dea7b17235a2a000001").first
97
149
  #
98
150
  # @return [ Criteria ] The deleted criteria.
151
+ #
152
+ # @since 1.0.0
99
153
  def deleted
100
154
  where(:deleted_at.ne => nil)
101
155
  end
@@ -2,9 +2,7 @@ namespace :db do
2
2
 
3
3
  unless Rake::Task.task_defined?("db:drop")
4
4
  desc 'Drops all the collections for the database for the current Rails.env'
5
- task :drop => :environment do
6
- Mongoid.master.collections.select {|c| c.name !~ /system/ }.each { |c| c.drop }
7
- end
5
+ task :drop => "mongoid:drop"
8
6
  end
9
7
 
10
8
  unless Rake::Task.task_defined?("db:seed")
@@ -171,6 +169,11 @@ namespace :db do
171
169
  end
172
170
  end
173
171
 
172
+ desc "Drops the database for the current Rails.env"
173
+ task :drop => :environment do
174
+ Mongoid.master.collections.select {|c| c.name !~ /system/ }.each { |c| c.drop }
175
+ end
176
+
174
177
  ########
175
178
  # TODO: lots more useful db tasks can be added here. stuff like copyDatabase, etc
176
179
  ########
@@ -125,5 +125,20 @@ module Mongoid # :nodoc:
125
125
  end
126
126
  end
127
127
  end
128
+
129
+ module ClassMethods #:nodoc:
130
+
131
+ # This is convenience for librarys still on the old API.
132
+ #
133
+ # @example Get the associations.
134
+ # Person.associations
135
+ #
136
+ # @return [ Hash ] The relations.
137
+ #
138
+ # @since 2.3.1
139
+ def associations
140
+ self.relations
141
+ end
142
+ end
128
143
  end
129
144
  end
@@ -31,7 +31,7 @@ module Mongoid # :nodoc:
31
31
  if inverse_metadata != metadata && !inverse_metadata.nil?
32
32
  base.metadata = inverse_metadata
33
33
  if base.referenced_many?
34
- target.send(inverse).push(base)
34
+ target.send(inverse).push(base) unless Mongoid.identity_map_enabled?
35
35
  else
36
36
  target.do_or_do_not(metadata.inverse_setter(target), base)
37
37
  end