mongoid 8.0.7 → 8.0.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ffe4422a33c5d676a4ae8e28c2d3ea748a738022b5fe0defa69a675fefbff8d
4
- data.tar.gz: d296900948d3e569beb33f4c63876ac24c45368dd0f3000efebecdcaed2cfbcf
3
+ metadata.gz: 4d604924530b809dbef3eef08d7e3c52b14e815d674821789a98c590f704b149
4
+ data.tar.gz: bfefc068fa68ed135560cff738dd7641f7df3780d01600a9f936752d5c760b8c
5
5
  SHA512:
6
- metadata.gz: 3632cdca025ba56792b041d07a560d00f3a561fa21ca9b0f44167fbf54b14fe0cc5ae040adeff7a24ac98795f6a54cfbfcd88ae3057906a44d606573e18ee398
7
- data.tar.gz: 243a702300881cc8ef82f7937e8ff3ea718b2c23aea8768a6392d47b6f3f841dba062e0133d142855b9f9ccf85f3bfbe0f45b743daed7f82813e02f6b9a1674b
6
+ metadata.gz: 50280304426a7dc55cb2e86d2ce69d295f5b51df6f714dee96e4a5c0b8da00c1ca09ad516d300da6755cf5160699a982868bb46c1afd2da812f952ca8c18e240
7
+ data.tar.gz: 0fccee8bb9add55b0dfaa6454a33c89fe40553ce1a3fe9bef8be36fe4c92a884970d2e2b2a44c32761a198e750351276ef38f27a5e95f7fe11be02686425568b
checksums.yaml.gz.sig CHANGED
Binary file
@@ -178,13 +178,15 @@ module Mongoid
178
178
  #
179
179
  # @return [ Object ] The associated path.
180
180
  def atomic_paths
181
- @atomic_paths ||= begin
182
- if _association
183
- _association.path(self)
184
- else
185
- Atomic::Paths::Root.new(self)
186
- end
187
- end
181
+ return @atomic_paths if @atomic_paths
182
+
183
+ paths = if _association
184
+ _association.path(self)
185
+ else
186
+ Atomic::Paths::Root.new(self)
187
+ end
188
+
189
+ paths.tap { @atomic_paths = paths unless new_record? }
188
190
  end
189
191
 
190
192
  # Get all the attributes that need to be pulled.
@@ -15,32 +15,110 @@ module Mongoid
15
15
  #
16
16
  # validates_associated :name, :addresses
17
17
  # end
18
- class AssociatedValidator < ActiveModel::EachValidator
18
+ class AssociatedValidator < ActiveModel::Validator
19
+ # Required by `validates_with` so that the validator
20
+ # gets added to the correct attributes.
21
+ def attributes
22
+ options[:attributes]
23
+ end
19
24
 
20
- # Validates that the associations provided are either all nil or all
21
- # valid. If neither is true then the appropriate errors will be added to
22
- # the parent document.
25
+ # Checks that the named associations of the given record
26
+ # (`attributes`) are valid. This does NOT load the associations
27
+ # from the database, and will only validate records that are dirty
28
+ # or unpersisted.
23
29
  #
24
- # @example Validate the association.
25
- # validator.validate_each(document, :name, name)
30
+ # If anything is not valid, appropriate errors will be added to
31
+ # the `document` parameter.
32
+ #
33
+ # @param [ Mongoid::Document ] document the document with the
34
+ # associations to validate.
35
+ def validate(document)
36
+ options[:attributes].each do |attr_name|
37
+ validate_association(document, attr_name)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # Validates that the given association provided is either nil,
44
+ # persisted and unchanged, or invalid. Otherwise, the appropriate errors
45
+ # will be added to the parent document.
26
46
  #
27
47
  # @param [ Document ] document The document to validate.
28
48
  # @param [ Symbol ] attribute The association to validate.
29
- # @param [ Object ] value The value of the association.
30
- def validate_each(document, attribute, value)
31
- begin
32
- document.begin_validate
33
- valid = Array.wrap(value).collect do |doc|
34
- if doc.nil? || doc.flagged_for_destroy?
35
- true
49
+ def validate_association(document, attribute)
50
+ # grab the proxy from the instance variable directly; we don't want
51
+ # any loading logic to run; we just want to see if it's already
52
+ # been loaded.
53
+ proxy = document.ivar(attribute)
54
+ return unless proxy
55
+
56
+ # if the variable exists, now we see if it is a proxy, or an actual
57
+ # document. It might be a literal document instead of a proxy if this
58
+ # document was created with a Document instance as a provided attribute,
59
+ # e.g. "Post.new(message: Message.new)".
60
+ target = proxy.respond_to?(:_target) ? proxy._target : proxy
61
+
62
+ # Now, fetch the list of documents from the target. Target may be a
63
+ # single value, or a list of values, and in the case of HasMany,
64
+ # might be a rather complex collection. We need to do this without
65
+ # triggering a load, so it's a bit of a delicate dance.
66
+ list = get_target_documents(target)
67
+
68
+ valid = document.validating do
69
+ # Now, treating the target as an array, look at each element
70
+ # and see if it is valid, but only if it has already been
71
+ # persisted, or changed, and hasn't been flagged for destroy.
72
+ list.all? do |value|
73
+ if value && !value.flagged_for_destroy? && (!value.persisted? || value.changed?)
74
+ value.validated? ? true : value.valid?
36
75
  else
37
- doc.validated? ? true : doc.valid?
76
+ true
38
77
  end
39
- end.all?
40
- ensure
41
- document.exit_validate
78
+ end
79
+ end
80
+
81
+ document.errors.add(attribute, :invalid) unless valid
82
+ end
83
+
84
+ private
85
+
86
+ # Examine the given target object and return an array of
87
+ # documents (possibly empty) that the target represents.
88
+ #
89
+ # @param [ Array | Mongoid::Document | Mongoid::Association::Proxy | HasMany::Enumerable ] target
90
+ # the target object to examine.
91
+ #
92
+ # @return [ Array<Mongoid::Document> ] the list of documents
93
+ def get_target_documents(target)
94
+ if target.respond_to?(:_loaded?)
95
+ get_target_documents_for_has_many(target)
96
+ else
97
+ get_target_documents_for_other(target)
42
98
  end
43
- document.errors.add(attribute, :invalid, **options) unless valid
99
+ end
100
+
101
+ # Returns the list of all currently in-memory values held by
102
+ # the target. The target will not be loaded.
103
+ #
104
+ # @param [ HasMany::Enumerable ] target the target that will
105
+ # be examined for in-memory documents.
106
+ #
107
+ # @return [ Array<Mongoid::Document> ] the in-memory documents
108
+ # held by the target.
109
+ def get_target_documents_for_has_many(target)
110
+ [ *target._loaded.values, *target._added.values ]
111
+ end
112
+
113
+ # Returns the target as an array. If the target represents a single
114
+ # value, it is wrapped in an array.
115
+ #
116
+ # @param [ Array | Mongoid::Document | Mongoid::Association::Proxy ] target
117
+ # the target to return.
118
+ #
119
+ # @return [ Array<Mongoid::Document> ] the target, as an array.
120
+ def get_target_documents_for_other(target)
121
+ Array.wrap(target)
44
122
  end
45
123
  end
46
124
  end
@@ -37,6 +37,14 @@ module Mongoid
37
37
  Threaded.exit_validate(self)
38
38
  end
39
39
 
40
+ # Perform a validation within the associated block.
41
+ def validating
42
+ begin_validate
43
+ yield
44
+ ensure
45
+ exit_validate
46
+ end
47
+
40
48
  # Given the provided options, are we performing validations?
41
49
  #
42
50
  # @example Are we performing validations?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mongoid
4
- VERSION = "8.0.7"
4
+ VERSION = "8.0.8"
5
5
  end
@@ -2,6 +2,28 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
+ module HabtmSpec
6
+ class Page
7
+ include Mongoid::Document
8
+ embeds_many :blocks, class_name: 'HabtmSpec::Block'
9
+ end
10
+
11
+ class Block
12
+ include Mongoid::Document
13
+ embedded_in :page, class_name: 'HabtmSpec::Page'
14
+ end
15
+
16
+ class ImageBlock < Block
17
+ has_and_belongs_to_many :attachments, inverse_of: nil, class_name: 'HabtmSpec::Attachment'
18
+ accepts_nested_attributes_for :attachments
19
+ end
20
+
21
+ class Attachment
22
+ include Mongoid::Document
23
+ field :file, type: String
24
+ end
25
+ end
26
+
5
27
  describe 'has_and_belongs_to_many associations' do
6
28
 
7
29
  context 'when an anonymous class defines a has_and_belongs_to_many association' do
@@ -18,4 +40,22 @@ describe 'has_and_belongs_to_many associations' do
18
40
  expect(klass.new.movies.build).to be_a Movie
19
41
  end
20
42
  end
43
+
44
+ context 'when an embedded has habtm relation' do
45
+ let(:attachment) { HabtmSpec::Attachment.create!(file: 'foo.jpg') }
46
+
47
+ let(:page) { HabtmSpec::Page.create! }
48
+
49
+ let(:image_block) do
50
+ image_block = page.blocks.build({
51
+ _type: 'HabtmSpec::ImageBlock',
52
+ attachment_ids: [ attachment.id.to_s ],
53
+ attachments_attributes: { '1234' => { file: 'bar.jpg', id: attachment.id.to_s } }
54
+ })
55
+ end
56
+
57
+ it 'does not raise on save' do
58
+ expect { image_block.save! }.not_to raise_error
59
+ end
60
+ end
21
61
  end
@@ -75,7 +75,6 @@ describe Mongoid::Validatable::AssociatedValidator do
75
75
  end
76
76
 
77
77
  it "does not run validation on them" do
78
- expect(description).to receive(:valid?).never
79
78
  expect(user).to be_valid
80
79
  end
81
80
 
@@ -84,14 +83,14 @@ describe Mongoid::Validatable::AssociatedValidator do
84
83
  end
85
84
  end
86
85
 
87
- describe "#validate_each" do
86
+ describe "#validate" do
88
87
 
89
88
  let(:person) do
90
89
  Person.new
91
90
  end
92
91
 
93
92
  let(:validator) do
94
- described_class.new(attributes: person.attributes)
93
+ described_class.new(attributes: person.relations.keys)
95
94
  end
96
95
 
97
96
  context "when the association is a one to one" do
@@ -99,7 +98,7 @@ describe Mongoid::Validatable::AssociatedValidator do
99
98
  context "when the association is nil" do
100
99
 
101
100
  before do
102
- validator.validate_each(person, :name, nil)
101
+ validator.validate(person)
103
102
  end
104
103
 
105
104
  it "adds no errors" do
@@ -108,14 +107,9 @@ describe Mongoid::Validatable::AssociatedValidator do
108
107
  end
109
108
 
110
109
  context "when the association is valid" do
111
-
112
- let(:associated) do
113
- double(valid?: true, flagged_for_destroy?: false)
114
- end
115
-
116
110
  before do
117
- expect(associated).to receive(:validated?).and_return(false)
118
- validator.validate_each(person, :name, associated)
111
+ person.name = Name.new(first_name: 'A', last_name: 'B')
112
+ validator.validate(person)
119
113
  end
120
114
 
121
115
  it "adds no errors" do
@@ -125,13 +119,9 @@ describe Mongoid::Validatable::AssociatedValidator do
125
119
 
126
120
  context "when the association is invalid" do
127
121
 
128
- let(:associated) do
129
- double(valid?: false, flagged_for_destroy?: false)
130
- end
131
-
132
122
  before do
133
- expect(associated).to receive(:validated?).and_return(false)
134
- validator.validate_each(person, :name, associated)
123
+ person.name = Name.new(first_name: 'Jamis', last_name: 'Buck')
124
+ validator.validate(person)
135
125
  end
136
126
 
137
127
  it "adds errors to the parent document" do
@@ -149,7 +139,7 @@ describe Mongoid::Validatable::AssociatedValidator do
149
139
  context "when the association is empty" do
150
140
 
151
141
  before do
152
- validator.validate_each(person, :addresses, [])
142
+ validator.validate(person)
153
143
  end
154
144
 
155
145
  it "adds no errors" do
@@ -159,13 +149,9 @@ describe Mongoid::Validatable::AssociatedValidator do
159
149
 
160
150
  context "when the association has invalid documents" do
161
151
 
162
- let(:associated) do
163
- double(valid?: false, flagged_for_destroy?: false)
164
- end
165
-
166
152
  before do
167
- expect(associated).to receive(:validated?).and_return(false)
168
- validator.validate_each(person, :addresses, [ associated ])
153
+ person.addresses << Address.new(street: '123')
154
+ validator.validate(person)
169
155
  end
170
156
 
171
157
  it "adds errors to the parent document" do
@@ -175,13 +161,10 @@ describe Mongoid::Validatable::AssociatedValidator do
175
161
 
176
162
  context "when the association has all valid documents" do
177
163
 
178
- let(:associated) do
179
- double(valid?: true, flagged_for_destroy?: false)
180
- end
181
-
182
164
  before do
183
- expect(associated).to receive(:validated?).and_return(false)
184
- validator.validate_each(person, :addresses, [ associated ])
165
+ person.addresses << Address.new(street: '123 First St')
166
+ person.addresses << Address.new(street: '456 Second St')
167
+ validator.validate(person)
185
168
  end
186
169
 
187
170
  it "adds no errors" do
@@ -4,6 +4,8 @@ class Name
4
4
  include Mongoid::Document
5
5
  include Mongoid::Attributes::Dynamic
6
6
 
7
+ validate :is_not_jamis
8
+
7
9
  field :_id, type: String, overwrite: true, default: ->{
8
10
  "#{first_name}-#{last_name}"
9
11
  }
@@ -23,4 +25,12 @@ class Name
23
25
  def set_parent=(set = false)
24
26
  self.parent_title = namable.title if set
25
27
  end
28
+
29
+ private
30
+
31
+ def is_not_jamis
32
+ if first_name == 'Jamis' && last_name == 'Buck'
33
+ errors.add(:base, :invalid)
34
+ end
35
+ end
26
36
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,18 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.7
4
+ version: 8.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - The MongoDB Ruby Team
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
13
  MIIEeDCCAuCgAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMREwDwYDVQQDDAhkYngt
14
14
  cnVieTEXMBUGCgmSJomT8ixkARkWB21vbmdvZGIxEzARBgoJkiaJk/IsZAEZFgNj
15
- b20wHhcNMjMwMTMxMTE1NjM1WhcNMjQwMTMxMTE1NjM1WjBBMREwDwYDVQQDDAhk
15
+ b20wHhcNMjQwMjA5MTc0NzIyWhcNMjUwMjA4MTc0NzIyWjBBMREwDwYDVQQDDAhk
16
16
  YngtcnVieTEXMBUGCgmSJomT8ixkARkWB21vbmdvZGIxEzARBgoJkiaJk/IsZAEZ
17
17
  FgNjb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC0/Veq9l47cTfX
18
18
  tQ+kHq2NOCwJuJGt1iXWQ/vH/yp7pZ/bLej7gPDl2CfIngAXRjM7r1FkR9ya7VAm
@@ -25,17 +25,17 @@ cert_chain:
25
25
  D+YQSuB2qYu021FI9zeY9sbZyWysEXBxhwrmTk+XUV0qz+OQZkMCAwEAAaN7MHkw
26
26
  CQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFH4nnr4tYlatU57RbExW
27
27
  jG86YM5nMB8GA1UdEQQYMBaBFGRieC1ydWJ5QG1vbmdvZGIuY29tMB8GA1UdEgQY
28
- MBaBFGRieC1ydWJ5QG1vbmdvZGIuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAVSlgM
29
- nFDWCCNLOCqG5/Lj4U62XoALkdCI+OZ30+WrA8qiRLSL9ZEziVK9AV7ylez+sriQ
30
- m8XKZKsCN5ON4+zXw1S+6Ftz/R4zDg7nTb9Wgw8ibzsoiP6e4pRW3Fls3ZdaG4pW
31
- +qMTbae9OiSrgI2bxNTII+v+1FcbQjOlMu8HPZ3ZfXnurXPgN5GxSyyclZI1QONO
32
- HbUoKHRirZu0F7JCvQQq4EkSuLWPplRJfYEeJIYm05zhhFeEyqea2B/TTlCtXa42
33
- 84vxXsxGzumuO8F2Q9m6/p95sNhqCp0B/SkKXIrRGJ7FBzupoORNRXHviS2OC3ty
34
- 4lwUzOlLTF/yO0wwYYfmtQOALQwKnW838vbYthMXvTjxB0EgVZ5PKto99WbjsXzy
35
- wkeAWhd5b+5JS0zgDL4SvGB8/W2IY+y0zELkojBMgJPyrpAWHL/WSsSBMuhyI2Pv
36
- xxaBVLklnJJ/qCCOZ3lG2MyVc/Nb0Mmq8ygWNsfwHmKKYuuWcviit0D0Tek=
28
+ MBaBFGRieC1ydWJ5QG1vbmdvZGIuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQBKGtHA
29
+ fpi3N/BL1J5O4CBsAjtF4jHDiw2r5MwK+66NzMh3uedjgPI7MoosemLy++SB+8BR
30
+ SE8bDkb6gfDQQzrI6KSXXyqH2TbQXpY5Tac7/yqXRiu8G2qOrOj4czB/Hq7j09CV
31
+ YoH88v6hL11i5jt6jPjFh8hXYG0hDQxhi3atRz5Wwd98tUf2DSbyJXJiRgCBeZjl
32
+ rP7AnKsWMu0C+zPlL+nXtQr+nTFtkKXRWfUJMqePpBqtriQvgQ+Y1ItqYVTSLuiM
33
+ iwUMcn/rGhdCMBSaKDXdFkIveCHQE2f2WBo2EdErrcTrgEKYYdNfzcb/43j7L1kx
34
+ AUwyTtk+HFrviBynQbKN82rjbZE+5gukVea5c7idQPkqacPYsoU37DI+hTlUyJkV
35
+ dcTtfEg44lLlfNukBslfiQf54r+uWbyB0m0rDUN/py7/Ghyzt5GLBU91uCO3dGoI
36
+ 55uFRHMvEcJMTDeImC/nuucPCAiEGMHggr9+NPC0tqpxjGKTo7lS7GzUFjg=
37
37
  -----END CERTIFICATE-----
38
- date: 2023-10-23 00:00:00.000000000 Z
38
+ date: 2024-02-28 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: activemodel
@@ -1163,7 +1163,7 @@ metadata:
1163
1163
  documentation_uri: https://docs.mongodb.com/mongoid/
1164
1164
  homepage_uri: https://mongoid.org/
1165
1165
  source_code_uri: https://github.com/mongodb/mongoid
1166
- post_install_message:
1166
+ post_install_message:
1167
1167
  rdoc_options: []
1168
1168
  require_paths:
1169
1169
  - lib
@@ -1178,8 +1178,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1178
1178
  - !ruby/object:Gem::Version
1179
1179
  version: 1.3.6
1180
1180
  requirements: []
1181
- rubygems_version: 3.4.21
1182
- signing_key:
1181
+ rubygems_version: 3.5.3
1182
+ signing_key:
1183
1183
  specification_version: 4
1184
1184
  summary: Elegant Persistence in Ruby for MongoDB.
1185
1185
  test_files:
metadata.gz.sig CHANGED
Binary file