mongoid 8.1.6 → 8.1.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: f4218c578b31195178d4f2425bf42c70741f23e123832c9dcc0df9794b1bfbaa
4
- data.tar.gz: 24b7b07e571fff97c9c35cc4f2477f6def8202211a35fb205711f73492f8f68c
3
+ metadata.gz: 8f349e627130f8eacea25a6242dbcb2d3c48e8c75c7740368afeb62e5939f7c3
4
+ data.tar.gz: 1acc6e8d45a07d5d6a140228804eb6f9cdb6b89ac8deeb39283c89338dbbf256
5
5
  SHA512:
6
- metadata.gz: 4086af26408203774f2c4861ae84707adea2dd45fff821470a9517e9ec10c41fc4c80a3e566a25118806e2d89311f6eb1aa8a9e27953ba5784cb22d78025e0ea
7
- data.tar.gz: 1b50e4fff002cc80175aa6c8e489f79c37f5b2cfebdf9adfe6da316b38bab18540a96717d7f217ed2054f7022faf4ec9eb42129e0474b59d3266c3585d237184
6
+ metadata.gz: 418c4bf1aac91a436d7d149b5961273c4f704b122d554f76dbe42ff6a29a777e5a3c7dc97c80900c3341cdaabc4e1536e883c00c283fd040cea05b352b2a0a5a
7
+ data.tar.gz: 65371b0d3a22ecbeeecae3a9091bc9540921155debff4b556419280bd5c76a3205125e9bb3bb781490031564f7a532dbebe68f72c5ba3c7542690ef3f5308173
data/Rakefile CHANGED
@@ -55,7 +55,7 @@ task :release do
55
55
  WARNING
56
56
  end
57
57
 
58
- system 'gem', 'push', "mongoid-#{Mongoid::VERSION}.gem"
58
+ system 'bundle', 'exec', 'gem', 'push', "mongoid-#{Mongoid::VERSION}.gem"
59
59
  end
60
60
 
61
61
  RSpec::Core::RakeTask.new("spec") do |spec|
@@ -22,7 +22,7 @@ module Mongoid
22
22
  # @return [ true | false ] If the document is new, or if the field is not
23
23
  # readonly.
24
24
  def attribute_writable?(name)
25
- new_record? || (!readonly_attributes.include?(name) && _loaded?(name))
25
+ new_record? || (!self.class.readonly_attributes.include?(name) && _loaded?(name))
26
26
  end
27
27
 
28
28
  private
@@ -62,12 +62,17 @@ module Mongoid
62
62
  # end
63
63
  #
64
64
  # @param [ Symbol... ] *names The names of the fields.
65
+ # @note When a parent class contains readonly attributes and is then
66
+ # inherited by a child class, the child class will inherit the
67
+ # parent's readonly attributes at the time of its creation.
68
+ # Updating the parent does not propagate down to child classes after wards.
65
69
  def attr_readonly(*names)
70
+ self.readonly_attributes = self.readonly_attributes.dup
66
71
  names.each do |name|
67
- readonly_attributes << database_field_name(name)
72
+ self.readonly_attributes << database_field_name(name)
68
73
  end
69
74
  end
70
75
  end
71
76
  end
72
77
  end
73
- end
78
+ end
@@ -552,7 +552,7 @@ module Mongoid
552
552
  # @return [ Selectable ] The new selectable.
553
553
  def not(*criteria)
554
554
  if criteria.empty?
555
- dup.tap { |query| query.negating = true }
555
+ dup.tap { |query| query.negating = !query.negating }
556
556
  else
557
557
  criteria.compact.inject(self.clone) do |c, new_s|
558
558
  if new_s.is_a?(Selectable)
@@ -133,7 +133,14 @@ module Mongoid
133
133
  #
134
134
  # @return [ Hash ] A hash of all attributes in the hierarchy.
135
135
  def as_document
136
- BSON::Document.new(as_attributes)
136
+ attrs = as_attributes
137
+
138
+ # legacy attributes have a tendency to leak internal state via
139
+ # `as_document`; we have to deep_dup the attributes here to prevent
140
+ # that.
141
+ attrs = attrs.deep_dup if Mongoid.legacy_attributes
142
+
143
+ BSON::Document.new(attrs)
137
144
  end
138
145
 
139
146
  # Calls #as_json on the document with additional, Mongoid-specific options.
@@ -17,6 +17,7 @@ module Mongoid
17
17
  #
18
18
  # @return [ Integer ] -1, 0, 1.
19
19
  def <=>(other)
20
+ return super unless other.is_a?(Mongoid::Equality)
20
21
  attributes["_id"].to_s <=> other.attributes["_id"].to_s
21
22
  end
22
23
 
@@ -35,11 +35,25 @@ module Mongoid
35
35
  # from and behaves identically to association traversal for the purposes
36
36
  # of, for example, subsequent array element retrieval.
37
37
  #
38
- # @param [ Document | Hash ] document The document to extract from.
38
+ # @param [ Document | Hash | String ] document The document to extract from.
39
39
  # @param [ String ] key The key path to extract.
40
40
  #
41
41
  # @return [ Object | Array ] Field value or values.
42
42
  module_function def extract_attribute(document, key)
43
+ # The matcher system will wind up sending atomic values to this as well,
44
+ # when attepting to match more complex types. If anything other than a
45
+ # Document or a Hash is given, we'll short-circuit the logic and just
46
+ # return an empty array.
47
+ return [] unless document.is_a?(Hash) || document.is_a?(Document)
48
+
49
+ # Performance optimization; if the key does not include a '.' character,
50
+ # it must reference an immediate attribute of the document.
51
+ unless key.include?('.')
52
+ hash = document.respond_to?(:attributes) ? document.attributes : document
53
+ key = find_exact_key(hash, key)
54
+ return key ? [ hash[key] ] : []
55
+ end
56
+
43
57
  if document.respond_to?(:as_attributes, true)
44
58
  # If a document has hash fields, as_attributes would keep those fields
45
59
  # as Hash instances which do not offer indifferent access.
@@ -12,13 +12,13 @@ module Mongoid
12
12
  included do
13
13
 
14
14
  class << self
15
- # Note that this intentionally only delegates :include_root_in_json
16
- # and not :include_root_in_json? - delegating the latter produces
17
- # wrong behavior.
18
- # Also note that this intentionally uses the ActiveSupport delegation
19
- # functionality and not the Ruby standard library one.
20
- # See https://jira.mongodb.org/browse/MONGOID-4849.
21
- delegate :include_root_in_json, to: ::Mongoid
15
+ def include_root_in_json
16
+ @include_root_in_json.nil? ? ::Mongoid.include_root_in_json : @include_root_in_json
17
+ end
18
+
19
+ def include_root_in_json=(new_value)
20
+ @include_root_in_json = new_value
21
+ end
22
22
  end
23
23
  end
24
24
 
@@ -7,6 +7,29 @@ module Mongoid
7
7
  # Provides behavior around traversing the document graph.
8
8
  module Traversable
9
9
  extend ActiveSupport::Concern
10
+ # This code is extracted from ActiveSupport so that we do not depend on
11
+ # their private API that may change at any time.
12
+ # This code should be reviewed and maybe removed when implementing
13
+ # https://jira.mongodb.org/browse/MONGOID-5832
14
+ class << self
15
+ # @api private
16
+ def __redefine(owner, name, value)
17
+ if owner.singleton_class?
18
+ owner.redefine_method(name) { value }
19
+ owner.send(:public, name)
20
+ end
21
+ owner.redefine_singleton_method(name) { value }
22
+ owner.singleton_class.send(:public, name)
23
+ owner.redefine_singleton_method("#{name}=") do |new_value|
24
+ if owner.equal?(self)
25
+ value = new_value
26
+ else
27
+ ::Mongoid::Traversable.redefine(self, name, new_value)
28
+ end
29
+ end
30
+ owner.singleton_class.send(:public, "#{name}=")
31
+ end
32
+ end
10
33
 
11
34
  def _parent
12
35
  @__parent ||= nil
@@ -30,7 +53,7 @@ module Mongoid
30
53
  if value
31
54
  Mongoid::Fields::Validators::Macro.validate_field_name(self, value)
32
55
  value = value.to_s
33
- super
56
+ ::Mongoid::Traversable.__redefine(self, 'discriminator_key', value)
34
57
  else
35
58
  # When discriminator key is set to nil, replace the class's definition
36
59
  # of the discriminator key reader (provided by class_attribute earlier)
@@ -69,13 +69,16 @@ module Mongoid
69
69
  # Now, treating the target as an array, look at each element
70
70
  # and see if it is valid, but only if it has already been
71
71
  # persisted, or changed, and hasn't been flagged for destroy.
72
- list.all? do |value|
72
+ #
73
+ # use map.all? instead of just all?, because all? will do short-circuit
74
+ # evaluation and terminate on the first failed validation.
75
+ list.map do |value|
73
76
  if value && !value.flagged_for_destroy? && (!value.persisted? || value.changed?)
74
77
  value.validated? ? true : value.valid?
75
78
  else
76
79
  true
77
80
  end
78
- end
81
+ end.all?
79
82
  end
80
83
 
81
84
  document.errors.add(attribute, :invalid) unless valid
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mongoid
4
- VERSION = "8.1.6"
4
+ VERSION = "8.1.8"
5
5
  end
@@ -26,6 +26,8 @@ describe 'Mongoid application tests' do
26
26
  context 'demo application' do
27
27
  context 'sinatra' do
28
28
  it 'runs' do
29
+ skip 'https://jira.mongodb.org/browse/MONGOID-5826'
30
+
29
31
  clone_application(
30
32
  'https://github.com/mongoid/mongoid-demo',
31
33
  subdir: 'sinatra-minimal',
@@ -45,6 +47,8 @@ describe 'Mongoid application tests' do
45
47
 
46
48
  context 'rails-api' do
47
49
  it 'runs' do
50
+ skip 'https://jira.mongodb.org/browse/MONGOID-5826'
51
+
48
52
  clone_application(
49
53
  'https://github.com/mongoid/mongoid-demo',
50
54
  subdir: 'rails-api',
@@ -95,7 +99,7 @@ describe 'Mongoid application tests' do
95
99
  check_call(%w(rails new mongoid-test --skip-spring --skip-active-record), env: clean_env)
96
100
 
97
101
  Dir.chdir('mongoid-test') do
98
- adjust_app_gemfile
102
+ adjust_app_gemfile(add_sprockets: SpecConfig.instance.rails_version != '8.0')
99
103
  check_call(%w(bundle install), env: clean_env)
100
104
 
101
105
  check_call(%w(rails g model post), env: clean_env)
@@ -117,7 +121,7 @@ describe 'Mongoid application tests' do
117
121
  check_call(%w(rails new mongoid-test-config --skip-spring --skip-active-record), env: clean_env)
118
122
 
119
123
  Dir.chdir('mongoid-test-config') do
120
- adjust_app_gemfile
124
+ adjust_app_gemfile(add_sprockets: SpecConfig.instance.rails_version != '8.0')
121
125
  check_call(%w(bundle install), env: clean_env)
122
126
 
123
127
  mongoid_config_file = File.join(TMP_BASE,'mongoid-test-config/config/mongoid.yml')
@@ -139,7 +143,7 @@ describe 'Mongoid application tests' do
139
143
  if (rails_version = SpecConfig.instance.rails_version) == 'master'
140
144
  else
141
145
  check_call(%w(gem list))
142
- check_call(%w(gem install rails --no-document -v) + ["~> #{rails_version}.0"])
146
+ check_call(%w(gem install rails --no-document --force -v) + ["~> #{rails_version}.0"])
143
147
  end
144
148
  end
145
149
 
@@ -287,6 +291,10 @@ describe 'Mongoid application tests' do
287
291
  end
288
292
 
289
293
  def adjust_rails_defaults(rails_version: SpecConfig.instance.rails_version)
294
+ if !rails_version.match?(/^\d+\.\d+$/)
295
+ # This must be pre-release version, we trim it
296
+ rails_version = rails_version.split('.')[0..1].join('.')
297
+ end
290
298
  if File.exist?('config/application.rb')
291
299
  lines = IO.readlines('config/application.rb')
292
300
  lines.each do |line|
@@ -749,6 +749,10 @@ describe Mongoid::Association::Referenced::BelongsTo::Proxy do
749
749
  person.save!
750
750
  end
751
751
 
752
+ # NOTE: there as a bad interdependency here, with the auto_save_spec.rb
753
+ # file. If auto_save_spec.rb runs before this, the following specs fail
754
+ # with "undefined method `nullify' for an instance of Person".
755
+
752
756
  context "when parent exists" do
753
757
 
754
758
  context "when child is destroyed" do
@@ -265,7 +265,26 @@ describe Mongoid::Attributes::Readonly do
265
265
  expect(child.mother).to be_nil
266
266
  end
267
267
  end
268
+ end
269
+
270
+ context "when a subclass inherits readonly fields" do
271
+ let(:attributes) do
272
+ [:title, :terms]
273
+ end
274
+
275
+ before do
276
+ class OldPerson < Person
277
+ attr_readonly :age
278
+ end
279
+ end
268
280
 
281
+ it "ensures subclass inherits the readonly attributes from parent" do
282
+ expect(OldPerson.readonly_attributes.to_a).to include("title","terms")
283
+ end
284
+
285
+ it "ensures subclass does not modify parent's readonly attributes" do
286
+ expect(Person.readonly_attributes.to_a).not_to include("age")
287
+ end
269
288
  end
270
289
  end
271
290
  end
@@ -2059,6 +2059,35 @@ describe Mongoid::Criteria::Queryable::Selectable do
2059
2059
  end
2060
2060
  end
2061
2061
 
2062
+ describe "#not" do
2063
+ context "when negating a criterion" do
2064
+ let(:selection) do
2065
+ query.not(field: /value/)
2066
+ end
2067
+
2068
+ it "adds the $not selector" do
2069
+ expect(selection.selector).to eq({
2070
+ "field" => { "$not" => /value/ }
2071
+ })
2072
+ end
2073
+
2074
+ it "returns a cloned query" do
2075
+ expect(selection).to_not equal(query)
2076
+ end
2077
+
2078
+ context "when toggling negation state" do
2079
+ it "negates the negating value" do
2080
+ expect(query.negating).to be_nil
2081
+ negated_query = query.not
2082
+ expect(negated_query.negating).to be true
2083
+ double_negated_query = negated_query.not
2084
+ expect(double_negated_query.negating).to be false
2085
+ end
2086
+ end
2087
+ end
2088
+ end
2089
+
2090
+
2062
2091
  describe Symbol do
2063
2092
 
2064
2093
  describe "#all" do
@@ -591,6 +591,33 @@ describe Mongoid::Document do
591
591
  expect(person.as_document["addresses"].first).to have_key(:locations)
592
592
  end
593
593
 
594
+ context 'when modifying the returned object' do
595
+ let(:record) do
596
+ RootCategory.create(categories: [{ name: 'tests' }]).reload
597
+ end
598
+
599
+ shared_examples_for 'an object with protected internal state' do
600
+ it 'does not expose internal state' do
601
+ before_change = record.as_document.dup
602
+ record.categories.first.name = 'things'
603
+ after_change = record.as_document
604
+ expect(before_change['categories'].first['name']).not_to eq('things')
605
+ end
606
+ end
607
+
608
+ context 'when legacy_attributes is true' do
609
+ config_override :legacy_attributes, true
610
+
611
+ it_behaves_like 'an object with protected internal state'
612
+ end
613
+
614
+ context 'when legacy_attributes is false' do
615
+ config_override :legacy_attributes, false
616
+
617
+ it_behaves_like 'an object with protected internal state'
618
+ end
619
+ end
620
+
594
621
  context "with relation define store_as option in embeded_many" do
595
622
 
596
623
  let!(:phone) do
@@ -291,6 +291,12 @@ describe Mongoid::Equality do
291
291
  it "compares based on the document id" do
292
292
  expect(first <=> second).to eq(-1)
293
293
  end
294
+
295
+ it "doesn't break if one isn't a document" do
296
+ expect do
297
+ first <=> "Foo"
298
+ end.to_not raise_error
299
+ end
294
300
  end
295
301
 
296
302
  describe "#eql?" do
@@ -37,12 +37,18 @@ describe Mongoid::Validatable::AssociatedValidator do
37
37
  User.new(name: "test")
38
38
  end
39
39
 
40
- let(:description) do
40
+ let(:description1) do
41
+ Description.new
42
+ end
43
+
44
+ let(:description2) do
41
45
  Description.new
42
46
  end
43
47
 
44
48
  before do
45
- user.descriptions << description
49
+ user.descriptions << description1
50
+ user.descriptions << description2
51
+ user.valid?
46
52
  end
47
53
 
48
54
  it "only validates the parent once" do
@@ -50,12 +56,16 @@ describe Mongoid::Validatable::AssociatedValidator do
50
56
  end
51
57
 
52
58
  it "adds the errors from the relation" do
53
- user.valid?
54
59
  expect(user.errors[:descriptions]).to_not be_nil
55
60
  end
56
61
 
62
+ it 'reports all failed validations' do
63
+ errors = user.descriptions.flat_map { |d| d.errors[:details] }
64
+ expect(errors.length).to be == 2
65
+ end
66
+
57
67
  it "only validates the child once" do
58
- expect(description).to_not be_valid
68
+ expect(description1).to_not be_valid
59
69
  end
60
70
  end
61
71
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.1.6
4
+ version: 8.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - The MongoDB Ruby Team
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-09-20 00:00:00.000000000 Z
10
+ date: 2025-01-07 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activemodel
@@ -19,7 +18,7 @@ dependencies:
19
18
  version: '5.1'
20
19
  - - "<"
21
20
  - !ruby/object:Gem::Version
22
- version: '7.3'
21
+ version: '8.1'
23
22
  - - "!="
24
23
  - !ruby/object:Gem::Version
25
24
  version: 7.0.0
@@ -32,7 +31,7 @@ dependencies:
32
31
  version: '5.1'
33
32
  - - "<"
34
33
  - !ruby/object:Gem::Version
35
- version: '7.3'
34
+ version: '8.1'
36
35
  - - "!="
37
36
  - !ruby/object:Gem::Version
38
37
  version: 7.0.0
@@ -1146,7 +1145,6 @@ metadata:
1146
1145
  documentation_uri: https://www.mongodb.com/docs/mongoid/
1147
1146
  homepage_uri: https://mongoid.org/
1148
1147
  source_code_uri: https://github.com/mongodb/mongoid
1149
- post_install_message:
1150
1148
  rdoc_options: []
1151
1149
  require_paths:
1152
1150
  - lib
@@ -1161,8 +1159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1161
1159
  - !ruby/object:Gem::Version
1162
1160
  version: 1.3.6
1163
1161
  requirements: []
1164
- rubygems_version: 3.4.19
1165
- signing_key:
1162
+ rubygems_version: 3.6.2
1166
1163
  specification_version: 4
1167
1164
  summary: Elegant Persistence in Ruby for MongoDB.
1168
1165
  test_files: