mongoid 8.0.7 → 8.0.8

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