mongoid 2.2.6 → 2.3.0

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 (80) hide show
  1. data/CHANGELOG.md +2 -858
  2. data/Rakefile +2 -5
  3. data/lib/mongoid.rb +1 -1
  4. data/lib/mongoid/attributes.rb +68 -18
  5. data/lib/mongoid/attributes/processing.rb +4 -3
  6. data/lib/mongoid/callbacks.rb +102 -0
  7. data/lib/mongoid/collection.rb +1 -1
  8. data/lib/mongoid/components.rb +2 -1
  9. data/lib/mongoid/contexts/enumerable.rb +0 -24
  10. data/lib/mongoid/contexts/mongo.rb +2 -2
  11. data/lib/mongoid/copyable.rb +3 -1
  12. data/lib/mongoid/criteria.rb +18 -10
  13. data/lib/mongoid/criterion/complex.rb +11 -0
  14. data/lib/mongoid/criterion/inclusion.rb +38 -7
  15. data/lib/mongoid/criterion/optional.rb +2 -7
  16. data/lib/mongoid/criterion/selector.rb +1 -0
  17. data/lib/mongoid/dirty.rb +19 -0
  18. data/lib/mongoid/document.rb +16 -12
  19. data/lib/mongoid/extensions/hash/criteria_helpers.rb +1 -1
  20. data/lib/mongoid/extensions/object/checks.rb +4 -1
  21. data/lib/mongoid/extensions/object_id/conversions.rb +4 -2
  22. data/lib/mongoid/extensions/string/inflections.rb +2 -2
  23. data/lib/mongoid/factory.rb +7 -2
  24. data/lib/mongoid/fields.rb +4 -10
  25. data/lib/mongoid/fields/serializable.rb +18 -2
  26. data/lib/mongoid/fields/serializable/integer.rb +17 -5
  27. data/lib/mongoid/fields/serializable/localized.rb +41 -0
  28. data/lib/mongoid/finders.rb +5 -4
  29. data/lib/mongoid/hierarchy.rb +87 -84
  30. data/lib/mongoid/identity.rb +4 -2
  31. data/lib/mongoid/keys.rb +2 -1
  32. data/lib/mongoid/logger.rb +1 -7
  33. data/lib/mongoid/matchers/and.rb +30 -0
  34. data/lib/mongoid/matchers/in.rb +1 -1
  35. data/lib/mongoid/matchers/nin.rb +1 -1
  36. data/lib/mongoid/matchers/strategies.rb +6 -4
  37. data/lib/mongoid/multi_parameter_attributes.rb +3 -2
  38. data/lib/mongoid/named_scope.rb +3 -13
  39. data/lib/mongoid/nested_attributes.rb +1 -1
  40. data/lib/mongoid/paranoia.rb +2 -3
  41. data/lib/mongoid/persistence.rb +9 -5
  42. data/lib/mongoid/persistence/atomic/operation.rb +1 -1
  43. data/lib/mongoid/persistence/deletion.rb +1 -1
  44. data/lib/mongoid/persistence/insertion.rb +1 -1
  45. data/lib/mongoid/persistence/modification.rb +1 -1
  46. data/lib/mongoid/railtie.rb +1 -1
  47. data/lib/mongoid/railties/database.rake +9 -1
  48. data/lib/mongoid/relations.rb +1 -0
  49. data/lib/mongoid/relations/accessors.rb +1 -1
  50. data/lib/mongoid/relations/builders.rb +6 -4
  51. data/lib/mongoid/relations/builders/referenced/many.rb +1 -23
  52. data/lib/mongoid/relations/builders/referenced/one.rb +1 -1
  53. data/lib/mongoid/relations/cascading.rb +5 -3
  54. data/lib/mongoid/relations/conversions.rb +35 -0
  55. data/lib/mongoid/relations/embedded/atomic.rb +3 -3
  56. data/lib/mongoid/relations/embedded/in.rb +1 -1
  57. data/lib/mongoid/relations/embedded/many.rb +16 -13
  58. data/lib/mongoid/relations/embedded/one.rb +3 -3
  59. data/lib/mongoid/relations/metadata.rb +19 -15
  60. data/lib/mongoid/relations/proxy.rb +4 -5
  61. data/lib/mongoid/relations/referenced/in.rb +1 -1
  62. data/lib/mongoid/relations/referenced/many.rb +12 -31
  63. data/lib/mongoid/relations/referenced/many_to_many.rb +4 -5
  64. data/lib/mongoid/relations/referenced/one.rb +6 -8
  65. data/lib/mongoid/relations/synchronization.rb +3 -5
  66. data/lib/mongoid/safety.rb +34 -4
  67. data/lib/mongoid/serialization.rb +20 -6
  68. data/lib/mongoid/threaded.rb +47 -0
  69. data/lib/mongoid/timestamps.rb +1 -0
  70. data/lib/mongoid/timestamps/created.rb +1 -8
  71. data/lib/mongoid/timestamps/timeless.rb +50 -0
  72. data/lib/mongoid/timestamps/updated.rb +2 -9
  73. data/lib/mongoid/validations.rb +0 -2
  74. data/lib/mongoid/validations/associated.rb +1 -2
  75. data/lib/mongoid/validations/uniqueness.rb +89 -36
  76. data/lib/mongoid/version.rb +1 -1
  77. data/lib/mongoid/versioning.rb +5 -6
  78. data/lib/rails/generators/mongoid_generator.rb +1 -1
  79. data/lib/rails/mongoid.rb +14 -5
  80. metadata +27 -23
@@ -1,6 +1,5 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
-
4
3
  module Timestamps
5
4
  # This module handles the behaviour for setting up document updated at
6
5
  # timestamp.
@@ -8,16 +7,10 @@ module Mongoid #:nodoc:
8
7
  extend ActiveSupport::Concern
9
8
 
10
9
  included do
11
- field :updated_at, :type => Time
12
-
10
+ field :updated_at, :type => Time, :versioned => false
13
11
  set_callback :save, :before, :set_updated_at, :if => Proc.new { |doc|
14
- doc.new_record? || doc.changed?
12
+ doc.timestamping? && (doc.new_record? || doc.changed?)
15
13
  }
16
-
17
- unless methods.include? 'record_timestamps'
18
- class_attribute :record_timestamps
19
- self.record_timestamps = true
20
- end
21
14
  end
22
15
 
23
16
  # Update the updated_at field on the Document to the current time.
@@ -44,9 +44,7 @@ module Mongoid #:nodoc:
44
44
  # @since 2.0.0.rc.1
45
45
  def read_attribute_for_validation(attr)
46
46
  if relations[attr.to_s]
47
- begin_validate
48
47
  relation = send(attr)
49
- exit_validate
50
48
  relation.do_or_do_not(:in_memory) || relation
51
49
  else
52
50
  send(attr)
@@ -39,8 +39,7 @@ module Mongoid #:nodoc:
39
39
  ensure
40
40
  document.exit_validate
41
41
  end
42
- return if valid
43
- document.errors.add(attribute, :invalid, options.merge(:value => value))
42
+ document.errors.add(attribute, :invalid) unless valid
44
43
  end
45
44
  end
46
45
  end
@@ -14,8 +14,16 @@ module Mongoid #:nodoc:
14
14
  # validates_uniqueness_of :title
15
15
  # end
16
16
  class UniquenessValidator < ActiveModel::EachValidator
17
+ attr_reader :klass
17
18
 
18
19
  # Unfortunately, we have to tie Uniqueness validators to a class.
20
+ #
21
+ # @example Setup the validator.
22
+ # UniquenessValidator.new.setup(Person)
23
+ #
24
+ # @param [ Class ] klass The class getting validated.
25
+ #
26
+ # @since 1.0.0
19
27
  def setup(klass)
20
28
  @klass = klass
21
29
  end
@@ -29,57 +37,102 @@ module Mongoid #:nodoc:
29
37
  # @param [ Symbol ] attribute The field to validate on.
30
38
  # @param [ Object ] value The value of the field.
31
39
  #
32
- # @todo Durran: This method needs refactoring.
40
+ # @return [ Errors ] The errors.
41
+ #
42
+ # @since 1.0.0
33
43
  def validate_each(document, attribute, value)
34
44
  if document.embedded?
35
- return if document._parent.nil?
36
- criteria = document._parent.send(document.metadata.name)
37
- # If the parent document embeds_one, no need to validate uniqueness
38
- return if criteria.is_a?(Mongoid::Document)
39
- criteria = criteria.where(attribute => unique_search_value(value), :_id => {'$ne' => document._id})
45
+ return if skip_validation?(document)
46
+ relation = document._parent.send(document.metadata.name)
47
+ criteria = relation.where(criterion(document, attribute, value))
40
48
  else
41
- criteria = @klass.where(attribute => unique_search_value(value))
42
- unless document.new_record?
43
- criteria = criteria.where(:_id => {'$ne' => document._id})
44
- end
45
- end
46
-
47
- Array.wrap(options[:scope]).each do |item|
48
- criteria = criteria.where(item => document.attributes[item.to_s])
49
- end
50
- if criteria.exists?
51
- document.errors.add(
52
- attribute,
53
- :taken,
54
- options.except(:case_sensitive, :scope).merge(:value => value)
55
- )
49
+ criteria = klass.where(criterion(document, attribute, value))
56
50
  end
51
+ criteria = scope(criteria, document, attribute)
52
+ document.errors.add(attribute, :taken) if criteria.exists?
57
53
  end
58
54
 
59
55
  protected
60
56
 
61
- # Determine if the primary key has changed on the document.
57
+ # Should the uniqueness validation be case sensitive?
62
58
  #
63
- # @example Has the key changed?
64
- # key_changed?(document)
59
+ # @example Is the validation case sensitive?
60
+ # validator.case_sensitive?
65
61
  #
66
- # @param [ Document ] document The document to check.
62
+ # @return [ true, false ] If the validation is case sensitive.
67
63
  #
68
- # @return [ true, false ] True if changed, false if not.
69
- def key_changed?(document)
70
- (document.primary_key || {}).each do |key|
71
- return true if document.send("#{key}_changed?")
72
- end; false
64
+ # @since 2.3.0
65
+ def case_sensitive?
66
+ !(options[:case_sensitive] == false)
73
67
  end
74
68
 
75
- # ensure :case_sensitive is true by default
76
- def unique_search_value(value)
77
- if options[:case_sensitive] == false
78
- value ? Regexp.new("^#{Regexp.escape(value.to_s)}$", Regexp::IGNORECASE) : nil
79
- else
80
- value
69
+ # Get the default criteria for checking uniqueness.
70
+ #
71
+ # @example Get the criteria.
72
+ # validator.criterion(person, :title, "Sir")
73
+ #
74
+ # @param [ Document ] document The document to validate.
75
+ # @param [ Symbol ] attribute The name of the attribute.
76
+ # @param [ Object ] value The value of the object.
77
+ #
78
+ # @return [ Criteria ] The uniqueness criteria.
79
+ #
80
+ # @since 2.3.0
81
+ def criterion(document, attribute, value)
82
+ { attribute => filter(value) }.tap do |selector|
83
+ if document.persisted? || document.embedded?
84
+ selector.merge!(:_id => { "$ne" => document.id })
85
+ end
81
86
  end
82
87
  end
88
+
89
+ # Filter the value based on whether the check is case sensitive or not.
90
+ #
91
+ # @example Filter the value.
92
+ # validator.filter("testing")
93
+ #
94
+ # @param [ Object ] value The value to filter.
95
+ #
96
+ # @return [ Object, Regexp ] The value, filtered or not.
97
+ #
98
+ # @since 2.3.0
99
+ def filter(value)
100
+ !case_sensitive? && value ? /^#{Regexp.escape(value.to_s)}$/i : value
101
+ end
102
+
103
+ # Scope the criteria to the scope options provided.
104
+ #
105
+ # @example Scope the criteria.
106
+ # validator.scope(criteria, document)
107
+ #
108
+ # @param [ Criteria ] criteria The criteria to scope.
109
+ # @param [ Document ] document The document being validated.
110
+ #
111
+ # @return [ Criteria ] The scoped criteria.
112
+ #
113
+ # @since 2.3.0
114
+ def scope(criteria, document, attribute)
115
+ unless document.primary_key == Array.wrap(attribute)
116
+ Array.wrap(options[:scope]).each do |item|
117
+ criteria = criteria.where(item => document.attributes[item.to_s])
118
+ end
119
+ end
120
+ criteria
121
+ end
122
+
123
+ # Should validation be skipped?
124
+ #
125
+ # @example Should the validation be skipped?
126
+ # validator.skip_validation?(doc)
127
+ #
128
+ # @param [ Document ] document The embedded document.
129
+ #
130
+ # @return [ true, false ] If the validation should be skipped.
131
+ #
132
+ # @since 2.3.0
133
+ def skip_validation?(document)
134
+ !document._parent || document.embedded_one?
135
+ end
83
136
  end
84
137
  end
85
138
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc
3
- VERSION = "2.2.6"
3
+ VERSION = "2.3.0"
4
4
  end
@@ -15,6 +15,7 @@ module Mongoid #:nodoc:
15
15
  :class_name => self.name,
16
16
  :validate => false,
17
17
  :cyclic => true,
18
+ :inverse_of => nil,
18
19
  :versioned => true
19
20
 
20
21
  set_callback :save, :before, :revise, :if => :revisable?
@@ -47,9 +48,9 @@ module Mongoid #:nodoc:
47
48
  def revise
48
49
  previous = previous_revision
49
50
  if previous && versioned_attributes_changed?
50
- versions.build(previous.versioned_attributes)
51
+ versions.build(previous.versioned_attributes).attributes.delete("_id")
51
52
  if version_max.present? && versions.length > version_max
52
- versions.delete(versions.first)
53
+ versions.shift
53
54
  end
54
55
  self.version = (version || 1 ) + 1
55
56
  end
@@ -64,9 +65,7 @@ module Mongoid #:nodoc:
64
65
  # @since 2.2.1
65
66
  def revise!
66
67
  new_version = versions.build((previous_revision || self).versioned_attributes)
67
- if version_max.present? && versions.length > version_max
68
- versions.delete(versions.first)
69
- end
68
+ versions.shift if version_max.present? && versions.length > version_max
70
69
  self.version = (version || 1 ) + 1
71
70
  save
72
71
  end
@@ -171,7 +170,7 @@ module Mongoid #:nodoc:
171
170
  # @since 2.1.0
172
171
  def only_versioned_attributes(hash)
173
172
  {}.tap do |versioned|
174
- hash.except("versions", "_id").each_pair do |name, value|
173
+ hash.except("versions").each_pair do |name, value|
175
174
  field = fields[name]
176
175
  versioned[name] = value if !field || field.versioned?
177
176
  end
@@ -63,7 +63,7 @@ module Rails
63
63
  def type_class
64
64
  return "Time" if type.to_s == "datetime"
65
65
  return "String" if type.to_s == "text"
66
- return type.to_s.camelcase
66
+ type.to_s.camelcase
67
67
  end
68
68
  end
69
69
  end
@@ -36,7 +36,6 @@ module Rails #:nodoc:
36
36
  #
37
37
  # @param [ Application ] app The rails application.
38
38
  def load_models(app)
39
- return unless ::Mongoid.preload_models
40
39
  app.config.paths["app/models"].each do |path|
41
40
  Dir.glob("#{path}/**/*.rb").sort.each do |file|
42
41
  load_model(file.gsub("#{path}/" , "").gsub(".rb", ""))
@@ -44,6 +43,14 @@ module Rails #:nodoc:
44
43
  end
45
44
  end
46
45
 
46
+ # Conditionally calls `Rails::Mongoid.load_models(app)` if the
47
+ # `::Mongoid.preload_models` is `true`.
48
+ #
49
+ # @param [ Application ] app The rails application.
50
+ def preload_models(app)
51
+ load_models(app) if ::Mongoid.preload_models
52
+ end
53
+
47
54
  private
48
55
 
49
56
  # I don't want to mock out kernel for unit testing purposes, so added this
@@ -70,10 +77,12 @@ module Rails #:nodoc:
70
77
  #
71
78
  # @since 2.1.0
72
79
  def determine_model(file)
73
- model_path = file[0..-4].split('/')[2..-1]
74
- klass = model_path.map { |path| path.camelize }.join('::').constantize
75
- if klass.ancestors.include?(::Mongoid::Document) && !klass.embedded
76
- return klass
80
+ if file =~ /app\/models\/(.*).rb$/
81
+ model_path = $1.split('/')
82
+ klass = model_path.map { |path| path.camelize }.join('::').constantize
83
+ if klass.ancestors.include?(::Mongoid::Document) && !klass.embedded
84
+ return klass
85
+ end
77
86
  end
78
87
  end
79
88
  end
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: 2.2.6
4
+ version: 2.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-22 00:00:00.000000000 Z
12
+ date: 2011-10-03 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
16
- requirement: &70168480357500 !ruby/object:Gem::Requirement
16
+ requirement: &70134095171800 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 3.0.0
21
+ version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70168480357500
24
+ version_requirements: *70134095171800
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: tzinfo
27
- requirement: &70168480357020 !ruby/object:Gem::Requirement
27
+ requirement: &70134095170860 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,21 +32,21 @@ dependencies:
32
32
  version: 0.3.22
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70168480357020
35
+ version_requirements: *70134095170860
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: mongo
38
- requirement: &70168480356540 !ruby/object:Gem::Requirement
38
+ requirement: &70134095170140 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
42
42
  - !ruby/object:Gem::Version
43
- version: '1.3'
43
+ version: '1.4'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70168480356540
46
+ version_requirements: *70134095170140
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rdoc
49
- requirement: &70168480356060 !ruby/object:Gem::Requirement
49
+ requirement: &70134095169380 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,21 +54,21 @@ dependencies:
54
54
  version: 3.5.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70168480356060
57
+ version_requirements: *70134095169380
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: bson_ext
60
- requirement: &70168480355580 !ruby/object:Gem::Requirement
60
+ requirement: &70134095168180 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
64
64
  - !ruby/object:Gem::Version
65
- version: '1.3'
65
+ version: '1.4'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70168480355580
68
+ version_requirements: *70134095168180
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: mocha
71
- requirement: &70168480355100 !ruby/object:Gem::Requirement
71
+ requirement: &70134095167500 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 0.9.12
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70168480355100
79
+ version_requirements: *70134095167500
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &70168480354620 !ruby/object:Gem::Requirement
82
+ requirement: &70134095166120 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '2.6'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70168480354620
90
+ version_requirements: *70134095166120
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: watchr
93
- requirement: &70168480354140 !ruby/object:Gem::Requirement
93
+ requirement: &70134095164880 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0.6'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70168480354140
101
+ version_requirements: *70134095164880
102
102
  description: Mongoid is an ODM (Object Document Mapper) Framework for MongoDB, written
103
103
  in Ruby.
104
104
  email:
@@ -215,6 +215,7 @@ files:
215
215
  - lib/mongoid/fields/serializable/foreign_keys/object.rb
216
216
  - lib/mongoid/fields/serializable/hash.rb
217
217
  - lib/mongoid/fields/serializable/integer.rb
218
+ - lib/mongoid/fields/serializable/localized.rb
218
219
  - lib/mongoid/fields/serializable/nil_class.rb
219
220
  - lib/mongoid/fields/serializable/object.rb
220
221
  - lib/mongoid/fields/serializable/object_id.rb
@@ -239,6 +240,7 @@ files:
239
240
  - lib/mongoid/keys.rb
240
241
  - lib/mongoid/logger.rb
241
242
  - lib/mongoid/matchers/all.rb
243
+ - lib/mongoid/matchers/and.rb
242
244
  - lib/mongoid/matchers/default.rb
243
245
  - lib/mongoid/matchers/exists.rb
244
246
  - lib/mongoid/matchers/gt.rb
@@ -312,6 +314,7 @@ files:
312
314
  - lib/mongoid/relations/cascading/strategy.rb
313
315
  - lib/mongoid/relations/cascading.rb
314
316
  - lib/mongoid/relations/constraint.rb
317
+ - lib/mongoid/relations/conversions.rb
315
318
  - lib/mongoid/relations/cyclic.rb
316
319
  - lib/mongoid/relations/embedded/atomic/operation.rb
317
320
  - lib/mongoid/relations/embedded/atomic/pull.rb
@@ -349,6 +352,7 @@ files:
349
352
  - lib/mongoid/state.rb
350
353
  - lib/mongoid/threaded.rb
351
354
  - lib/mongoid/timestamps/created.rb
355
+ - lib/mongoid/timestamps/timeless.rb
352
356
  - lib/mongoid/timestamps/updated.rb
353
357
  - lib/mongoid/timestamps.rb
354
358
  - lib/mongoid/validations/associated.rb
@@ -385,7 +389,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
385
389
  version: '0'
386
390
  segments:
387
391
  - 0
388
- hash: -2081146589811076586
392
+ hash: -2142678717423572392
389
393
  required_rubygems_version: !ruby/object:Gem::Requirement
390
394
  none: false
391
395
  requirements:
@@ -394,7 +398,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
394
398
  version: 1.3.6
395
399
  requirements: []
396
400
  rubyforge_project: mongoid
397
- rubygems_version: 1.8.10
401
+ rubygems_version: 1.8.6
398
402
  signing_key:
399
403
  specification_version: 3
400
404
  summary: Elegant Persistance in Ruby for MongoDB.