mongoid 8.1.4 → 8.1.5

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: '059cd4652349083d2098577aa1c6f1f90233ab91474ef0a3f97db4bef4843f9f'
4
- data.tar.gz: ca14035b9902221fe082862ea061f83beb2abc41a9a3eeb10dd0f781a34e697e
3
+ metadata.gz: dbe9ca12b60eeee360717af6f05117691a514c4b37f645c456b7c2675ab60606
4
+ data.tar.gz: 145e999e0a17a6eff2d19c7188a2aee7f27785308f507cd57df1d8ac74ebe93d
5
5
  SHA512:
6
- metadata.gz: 358e801040678c844022e9e41bcdd3a5d482cbafbe608b623340c834d4b72545df547afa83d861d64431703d198c4347f6d9bada41c2960d38b46fdc1a243855
7
- data.tar.gz: 8a2981f0a6d4bb4b2c24b6a636079ad3e3cbd1586791104deca7c118d0a08f8753a9a2ce564b416293ce337154c965f26a9ce34f44f087dd0fa8c981d58684da
6
+ metadata.gz: bb5249dd2e2eea2d2ba3fdfa2c84c3dbaa71b181e22ff2a181854ce029499cf723487b00ec4ad4eef0619fda4bfcf3b071f36dc436ef46321fcf7c99319124d4
7
+ data.tar.gz: 1ff5ba0852368f7f032c80e18bcfd27934ee35a3e91e84197e6641f0d966b914c29c5aac8cd4e81df720db2b8b8bd54c42fc25e9b2c8a9e8cf1fb33f9da8cc89
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.1.4"
4
+ VERSION = "8.1.5"
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
@@ -203,7 +203,6 @@ module Mrss
203
203
  'ubuntu2204' => 'ubuntu:jammy',
204
204
  'rhel62' => 'centos:6',
205
205
  'rhel70' => 'centos:7',
206
- # 'rhel80' => 'redhat/ubi8',
207
206
  'rhel80' => 'rockylinux:8',
208
207
  }.freeze
209
208
 
@@ -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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.1.4
4
+ version: 8.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - The MongoDB Ruby Team
@@ -12,7 +12,7 @@ cert_chain:
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-11-22 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
@@ -1211,7 +1211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1211
1211
  - !ruby/object:Gem::Version
1212
1212
  version: 1.3.6
1213
1213
  requirements: []
1214
- rubygems_version: 3.4.21
1214
+ rubygems_version: 3.5.3
1215
1215
  signing_key:
1216
1216
  specification_version: 4
1217
1217
  summary: Elegant Persistence in Ruby for MongoDB.
metadata.gz.sig CHANGED
Binary file