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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/mongoid/atomic.rb +9 -7
- data/lib/mongoid/validatable/associated.rb +96 -18
- data/lib/mongoid/validatable.rb +8 -0
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +40 -0
- data/spec/mongoid/validatable/associated_spec.rb +13 -30
- data/spec/support/models/name.rb +10 -0
- data.tar.gz.sig +0 -0
- metadata +16 -16
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d604924530b809dbef3eef08d7e3c52b14e815d674821789a98c590f704b149
|
4
|
+
data.tar.gz: bfefc068fa68ed135560cff738dd7641f7df3780d01600a9f936752d5c760b8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50280304426a7dc55cb2e86d2ce69d295f5b51df6f714dee96e4a5c0b8da00c1ca09ad516d300da6755cf5160699a982868bb46c1afd2da812f952ca8c18e240
|
7
|
+
data.tar.gz: 0fccee8bb9add55b0dfaa6454a33c89fe40553ce1a3fe9bef8be36fe4c92a884970d2e2b2a44c32761a198e750351276ef38f27a5e95f7fe11be02686425568b
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/mongoid/atomic.rb
CHANGED
@@ -178,13 +178,15 @@ module Mongoid
|
|
178
178
|
#
|
179
179
|
# @return [ Object ] The associated path.
|
180
180
|
def atomic_paths
|
181
|
-
@atomic_paths
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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::
|
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
|
-
#
|
21
|
-
# valid.
|
22
|
-
# the
|
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
|
-
#
|
25
|
-
#
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
76
|
+
true
|
38
77
|
end
|
39
|
-
end
|
40
|
-
|
41
|
-
|
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
|
-
|
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
|
data/lib/mongoid/validatable.rb
CHANGED
@@ -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?
|
data/lib/mongoid/version.rb
CHANGED
@@ -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 "#
|
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.
|
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.
|
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
|
-
|
118
|
-
validator.
|
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
|
-
|
134
|
-
validator.
|
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.
|
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
|
-
|
168
|
-
validator.
|
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
|
-
|
184
|
-
|
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
|
data/spec/support/models/name.rb
CHANGED
@@ -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.
|
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
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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:
|
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.
|
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
|