mongoid 2.2.6 → 2.3.0

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