mongoid 2.3.0 → 2.3.1

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