mongo_mapper 0.15.1 → 0.15.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -7
  3. data/lib/mongo_mapper/document.rb +1 -0
  4. data/lib/mongo_mapper/extensions/array.rb +1 -1
  5. data/lib/mongo_mapper/extensions/binary.rb +1 -1
  6. data/lib/mongo_mapper/extensions/date.rb +1 -1
  7. data/lib/mongo_mapper/extensions/float.rb +1 -1
  8. data/lib/mongo_mapper/extensions/hash.rb +1 -1
  9. data/lib/mongo_mapper/extensions/nil_class.rb +2 -2
  10. data/lib/mongo_mapper/extensions/object.rb +1 -1
  11. data/lib/mongo_mapper/extensions/object_id.rb +1 -1
  12. data/lib/mongo_mapper/extensions/set.rb +1 -1
  13. data/lib/mongo_mapper/extensions/string.rb +1 -1
  14. data/lib/mongo_mapper/plugins/associations/many_association.rb +2 -3
  15. data/lib/mongo_mapper/plugins/associations/{belongs_to_polymorphic_proxy.rb → proxy/belongs_to_polymorphic_proxy.rb} +0 -0
  16. data/lib/mongo_mapper/plugins/associations/{belongs_to_proxy.rb → proxy/belongs_to_proxy.rb} +6 -0
  17. data/lib/mongo_mapper/plugins/associations/proxy/collection.rb +55 -0
  18. data/lib/mongo_mapper/plugins/associations/{embedded_collection.rb → proxy/embedded_collection.rb} +0 -0
  19. data/lib/mongo_mapper/plugins/associations/{in_array_proxy.rb → proxy/in_array_proxy.rb} +0 -0
  20. data/lib/mongo_mapper/plugins/associations/{in_foreign_array_proxy.rb → proxy/in_foreign_array_proxy.rb} +0 -0
  21. data/lib/mongo_mapper/plugins/associations/{many_documents_as_proxy.rb → proxy/many_documents_as_proxy.rb} +0 -0
  22. data/lib/mongo_mapper/plugins/associations/{many_documents_proxy.rb → proxy/many_documents_proxy.rb} +0 -4
  23. data/lib/mongo_mapper/plugins/associations/{many_embedded_polymorphic_proxy.rb → proxy/many_embedded_polymorphic_proxy.rb} +0 -0
  24. data/lib/mongo_mapper/plugins/associations/{many_embedded_proxy.rb → proxy/many_embedded_proxy.rb} +0 -0
  25. data/lib/mongo_mapper/plugins/associations/{many_polymorphic_proxy.rb → proxy/many_polymorphic_proxy.rb} +0 -0
  26. data/lib/mongo_mapper/plugins/associations/{one_as_proxy.rb → proxy/one_as_proxy.rb} +0 -0
  27. data/lib/mongo_mapper/plugins/associations/{one_embedded_polymorphic_proxy.rb → proxy/one_embedded_polymorphic_proxy.rb} +0 -0
  28. data/lib/mongo_mapper/plugins/associations/{one_embedded_proxy.rb → proxy/one_embedded_proxy.rb} +3 -1
  29. data/lib/mongo_mapper/plugins/associations/{one_proxy.rb → proxy/one_proxy.rb} +0 -0
  30. data/lib/mongo_mapper/plugins/associations/{proxy.rb → proxy/proxy.rb} +69 -49
  31. data/lib/mongo_mapper/plugins/associations/single_association.rb +2 -11
  32. data/lib/mongo_mapper/plugins/dirty.rb +2 -2
  33. data/lib/mongo_mapper/plugins/embedded_document.rb +1 -1
  34. data/lib/mongo_mapper/plugins/keys/key.rb +9 -6
  35. data/lib/mongo_mapper/plugins/keys.rb +17 -7
  36. data/lib/mongo_mapper/plugins/querying.rb +2 -2
  37. data/lib/mongo_mapper/plugins/scopes.rb +19 -3
  38. data/lib/mongo_mapper/plugins/shardable.rb +30 -0
  39. data/lib/mongo_mapper/plugins/validations.rb +1 -1
  40. data/lib/mongo_mapper/version.rb +1 -1
  41. data/lib/mongo_mapper.rb +18 -18
  42. data/spec/examples.txt +1718 -1697
  43. data/spec/functional/associations/belongs_to_proxy_spec.rb +33 -0
  44. data/spec/functional/associations/one_embedded_proxy_spec.rb +28 -0
  45. data/spec/functional/associations/one_proxy_spec.rb +11 -1
  46. data/spec/functional/dirty_spec.rb +21 -0
  47. data/spec/functional/dirty_with_callbacks_spec.rb +59 -0
  48. data/spec/functional/keys_spec.rb +13 -0
  49. data/spec/functional/scopes_spec.rb +88 -0
  50. data/spec/functional/shardable_spec.rb +67 -0
  51. data/spec/spec_helper.rb +7 -0
  52. data/spec/unit/associations/proxy_spec.rb +30 -5
  53. data/spec/unit/extensions_spec.rb +9 -3
  54. data/spec/unit/inspect_spec.rb +1 -1
  55. data/spec/unit/key_spec.rb +7 -1
  56. metadata +36 -19
  57. data/lib/mongo_mapper/plugins/associations/collection.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77d669d6c4286995fb2afbed7cf23475c6dc496cb3faf97a57f3b8f115e263b3
4
- data.tar.gz: d11040bb05eeb6cb57465c4585c0667b16d750b16d7fd5fedca5e03734b769ac
3
+ metadata.gz: ae0bcdb6320444b591dc779d739c553ba371c86e8465c4547c5e35423fe37ade
4
+ data.tar.gz: 270341e4efc65ba09578c2ba889c3c2e560610cf6eddfa7889fee19ded37c760
5
5
  SHA512:
6
- metadata.gz: 56a665e63c65da52238cc18348333a2a9c6b6d1c5acf564308f60f8fcec8a1be759c5b7546a0259092a7f6acc9170659d55c462ac59fffe6520f3339a650df15
7
- data.tar.gz: 8dceac60d1ef1159585453450d2960e4d9d50e472ec7728f3b703da8e40e80af625b01bb6c4022327e16631960faa698da93c7d37c563cd1c839eb3ebfc28ddb
6
+ metadata.gz: 3af02a093ffb4f9b13f48557bd83689c5cdcf35e434c00b152be18ad33e520e9ffbf1b7817b90ac4d363fe6f4452bab2ee66c5c450aca65981cc29ac2e74fe89
7
+ data.tar.gz: '09f802a3351959d626e23b4a6fa331ef10749a3b2f259440b527b26a25a23d0f0684c1e2bf0001938357e76fe5664da481ff298b572e665ded6afe0feb5fb286'
data/README.md CHANGED
@@ -4,9 +4,9 @@ A Ruby Object Mapper for Mongo.
4
4
 
5
5
  [<img src="https://badge.fury.io/rb/mongo_mapper.svg" alt="RubyGems">](https://rubygems.org/gems/mongo_mapper)
6
6
 
7
- [<img src="https://travis-ci.org/mongomapper/mongomapper.svg?branch=master" alt="Build Status" />](https://travis-ci.org/mongomapper/mongomapper)
7
+ [<img src="https://github.com/mongomapper/mongomapper/workflows/Ruby/badge.svg?branch=master" alt="Build Status" />](https://github.com/mongomapper/mongomapper/actions?query=workflow%3ARuby+branch%3Amaster)
8
8
 
9
- [<img src="https://coveralls.io/repos/mongomapper/mongomapper/badge.svg" alt="Coverage Status" />](https://coveralls.io/r/mongomapper/mongomapper)
9
+ <!-- [<img src="https://coveralls.io/repos/mongomapper/mongomapper/badge.svg" alt="Coverage Status" />](https://coveralls.io/r/mongomapper/mongomapper) -->
10
10
 
11
11
  ## Install
12
12
 
@@ -18,16 +18,27 @@ http://mongomapper.com/documentation/
18
18
 
19
19
  http://rdoc.info/github/mongomapper/mongomapper
20
20
 
21
+ ## Open Commit Policy
22
+
23
+ Like Rubinius, we're trying out an "open commit policy".
24
+
25
+ If you've committed one (code) patch that has been accepted and would like to
26
+ work some more on the project, send an email to Scott Taylor
27
+ <scott@railsnewbie.com> along with your commit sha1.
28
+
21
29
  ## Compatibility
22
30
 
23
31
  MongoMapper is tested against:
24
32
 
25
- * MRI 2.4 - 2.7
33
+ * MRI 2.4 - 3.0.1
26
34
  * JRuby (Versions with 1.9 compatibility)
27
35
 
28
36
  Additionally, MongoMapper is tested against:
29
37
 
30
- * Rails 5.0+ - 6.0
38
+ * Rails 5.0 - 5.2
39
+ * Rails 6.0 - 6.1
40
+
41
+ Note, if you are using Ruby 3.0+, you'll need Rails 6.
31
42
 
32
43
  ## Contributing & Development
33
44
 
@@ -37,17 +48,21 @@ Additionally, MongoMapper is tested against:
37
48
 
38
49
  * Fork the project.
39
50
  * Make your feature addition or bug fix. All specs should pass.
40
- * Add specs for your changes. This is important so I don't break it in a future version unintentionally.
41
- * Commit, do not mess with Rakefile, version, or history. If you want to have your own version, that is fine but bump version in a commit by itself in another branch so a maintainer ignore it when your pull request is merged.
51
+ * Add specs for your changes. This is important so that it doesn't break in a future version.
52
+ * Commit, do not mess with Rakefile, version, or history. If you want to have your own version, that is fine but bump version in a commit by itself in another branch so a maintainer can ignore it when your pull request is merged.
42
53
  * Send a pull request. Bonus points for topic branches.
43
54
 
55
+ ## How to release
56
+
57
+ See `HOW_TO_RELEASE.md`
58
+
44
59
  ## Problems or Questions?
45
60
 
46
61
  Hit up the Google group: http://groups.google.com/group/mongomapper
47
62
 
48
63
  ## Copyright
49
64
 
50
- Copyright (c) 2009-2020 MongoMapper. See LICENSE for details.
65
+ Copyright (c) 2009-2021 MongoMapper. See LICENSE for details.
51
66
 
52
67
  ## Contributors
53
68
 
@@ -39,6 +39,7 @@ module MongoMapper
39
39
  include Plugins::PartialUpdates
40
40
  include Plugins::IdentityMap
41
41
  include Plugins::CounterCache
42
+ include Plugins::Shardable
42
43
 
43
44
  included do
44
45
  extend Plugins
@@ -24,4 +24,4 @@ end
24
24
 
25
25
  class Array
26
26
  include MongoMapper::Extensions::Array
27
- end
27
+ end
@@ -19,4 +19,4 @@ end
19
19
 
20
20
  class Binary
21
21
  extend MongoMapper::Extensions::Binary
22
- end
22
+ end
@@ -22,4 +22,4 @@ end
22
22
 
23
23
  class Date
24
24
  extend MongoMapper::Extensions::Date
25
- end
25
+ end
@@ -11,4 +11,4 @@ end
11
11
 
12
12
  class Float
13
13
  extend MongoMapper::Extensions::Float
14
- end
14
+ end
@@ -23,4 +23,4 @@ end
23
23
 
24
24
  class Hash
25
25
  include MongoMapper::Extensions::Hash
26
- end
26
+ end
@@ -14,5 +14,5 @@ module MongoMapper
14
14
  end
15
15
 
16
16
  class NilClass
17
- include MongoMapper::Extensions::NilClass
18
- end
17
+ extend MongoMapper::Extensions::NilClass
18
+ end
@@ -27,4 +27,4 @@ end
27
27
 
28
28
  class Object
29
29
  include MongoMapper::Extensions::Object
30
- end
30
+ end
@@ -33,4 +33,4 @@ class BSON::ObjectId
33
33
  def original_to_json(*args)
34
34
  original_as_json.to_json(*args)
35
35
  end
36
- end
36
+ end
@@ -17,4 +17,4 @@ end
17
17
 
18
18
  class Set
19
19
  extend MongoMapper::Extensions::Set
20
- end
20
+ end
@@ -23,4 +23,4 @@ end
23
23
 
24
24
  class String
25
25
  include MongoMapper::Extensions::String
26
- end
26
+ end
@@ -30,12 +30,11 @@ module MongoMapper
30
30
  def setup(model)
31
31
  model.associations_module.module_eval(<<-end_eval, __FILE__, __LINE__ + 1)
32
32
  def #{name}
33
- get_proxy(associations[#{name.inspect}])
33
+ get_proxy(associations[#{name.inspect}]).read
34
34
  end
35
35
 
36
36
  def #{name}=(value)
37
- get_proxy(associations[#{name.inspect}]).replace(value)
38
- value
37
+ get_proxy(associations[#{name.inspect}]).write(value)
39
38
  end
40
39
  end_eval
41
40
 
@@ -47,6 +47,12 @@ module MongoMapper
47
47
  loaded
48
48
  @target
49
49
  end
50
+
51
+ private
52
+
53
+ def stale_target?
54
+ loaded? && proxy_owner[association.foreign_key] != @target&.id
55
+ end
50
56
  end
51
57
  end
52
58
  end
@@ -0,0 +1,55 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class Collection < Proxy
6
+ include Enumerable
7
+
8
+ def to_a
9
+ load_target
10
+
11
+ target.is_a?(Array) ?
12
+ target :
13
+ Array(target)
14
+ end
15
+
16
+ alias_method :to_ary, :to_a
17
+
18
+ def each(&block)
19
+ to_a.each(&block)
20
+ end
21
+
22
+ def [](val)
23
+ objs = to_a
24
+ objs ? objs[val] : nil
25
+ end
26
+
27
+ def empty?
28
+ to_a.empty?
29
+ end
30
+
31
+ def size
32
+ to_a.size
33
+ end
34
+
35
+ def length
36
+ to_a.length
37
+ end
38
+
39
+ def reset
40
+ super
41
+ target = []
42
+ end
43
+
44
+ def read
45
+ self
46
+ end
47
+
48
+ def write(value)
49
+ replace(value)
50
+ read
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -76,10 +76,6 @@ module MongoMapper
76
76
  @target.each { |doc| doc.save(options) } if @target
77
77
  end
78
78
 
79
- def each(&block)
80
- load_target.each(&block)
81
- end
82
-
83
79
  protected
84
80
 
85
81
  def query(options={})
@@ -11,7 +11,9 @@ module MongoMapper
11
11
  end
12
12
 
13
13
  def replace(doc)
14
- if doc.respond_to?(:attributes)
14
+ if doc.instance_of?(klass)
15
+ @target = doc
16
+ elsif doc.respond_to?(:attributes)
15
17
  @target = klass.load(doc.attributes, true)
16
18
  else
17
19
  @target = klass.load(doc, true)
@@ -1,19 +1,25 @@
1
1
  # encoding: UTF-8
2
2
  require 'forwardable'
3
+
3
4
  module MongoMapper
4
5
  module Plugins
5
6
  module Associations
6
7
  class Proxy
7
8
  extend Forwardable
8
9
 
9
- alias :proxy_respond_to? :respond_to?
10
- alias :proxy_extend :extend
11
-
12
- instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^respond_to_missing\?$|^object_id$)/ }
10
+ class << self
11
+ def define_proxy_method(method)
12
+ define_method(method) do |*args, &block|
13
+ proxy_method(method, *args, &block)
14
+ end
15
+ end
16
+ end
13
17
 
14
18
  attr_reader :proxy_owner, :association, :target
15
19
 
16
- alias :proxy_association :association
20
+ alias_method :proxy_respond_to?, :respond_to?
21
+ alias_method :proxy_extend, :extend
22
+ alias_method :proxy_association, :association
17
23
 
18
24
  def_delegators :proxy_association, :klass, :options
19
25
  def_delegator :klass, :collection
@@ -24,26 +30,31 @@ module MongoMapper
24
30
  reset
25
31
  end
26
32
 
27
- # Active support in rails 3 beta 4 can override to_json after this is loaded,
28
- # at least when run in mongomapper tests. The implementation was changed in master
29
- # some time after this, so not sure whether this is still a problem.
30
- #
31
- # In rails 2, this isn't a problem however it also solves an issue where
32
- # to_json isn't forwarded because it supports to_json itself
33
- def to_json(*options)
34
- load_target
35
- target.to_json(*options)
36
- end
37
-
38
- # see comments to to_json
39
- def as_json(*options)
40
- load_target
41
- target.as_json(*options)
33
+ [
34
+ :is_a?,
35
+ :to_mongo,
36
+ :==,
37
+ :!=,
38
+ :nil?,
39
+ :blank?,
40
+ :present?,
41
+ :hash,
42
+ # Active support in rails 3 beta 4 can override to_json after this is loaded,
43
+ # at least when run in mongomapper tests. The implementation was changed in master
44
+ # some time after this, so not sure whether this is still a problem.
45
+ #
46
+ # In rails 2, this isn't a problem however it also solves an issue where
47
+ # to_json isn't forwarded because it supports to_json itself
48
+ :to_json,
49
+ # see comments to to_json
50
+ :as_json,
51
+ ].each do |m|
52
+ define_proxy_method(m)
42
53
  end
43
54
 
44
55
  def inspect
45
56
  load_target
46
- target.inspect
57
+ "#<#{self.class.inspect}:#{object_id} #{@target.inspect}>"
47
58
  end
48
59
 
49
60
  def loaded?
@@ -54,21 +65,6 @@ module MongoMapper
54
65
  @loaded = true
55
66
  end
56
67
 
57
- def nil?
58
- load_target
59
- target.nil?
60
- end
61
-
62
- def blank?
63
- load_target
64
- target.blank?
65
- end
66
-
67
- def present?
68
- load_target
69
- target.present?
70
- end
71
-
72
68
  def reload
73
69
  reset
74
70
  load_target
@@ -87,16 +83,7 @@ module MongoMapper
87
83
  end
88
84
 
89
85
  def respond_to?(*args)
90
- proxy_respond_to?(*args) || (load_target && target.respond_to?(*args))
91
- end
92
-
93
- def send(method, *args, &block)
94
- if proxy_respond_to?(method, true)
95
- super
96
- else
97
- load_target
98
- target.send(method, *args, &block)
99
- end
86
+ super || (load_target && target.respond_to?(*args))
100
87
  end
101
88
 
102
89
  def read
@@ -104,10 +91,20 @@ module MongoMapper
104
91
  @target
105
92
  end
106
93
 
94
+ def write(value)
95
+ replace(value)
96
+ read
97
+ end
98
+
99
+ def proxy_method(method, *args, &block)
100
+ load_target
101
+ target.public_send(method, *args, &block)
102
+ end
103
+
107
104
  protected
108
105
 
109
106
  def load_target
110
- unless loaded?
107
+ if !loaded? || stale_target?
111
108
  if @target.is_a?(Array) && @target.any?
112
109
  @target = find_target + @target.find_all { |record| !record.persisted? }
113
110
  else
@@ -134,9 +131,32 @@ module MongoMapper
134
131
 
135
132
  private
136
133
 
134
+ def stale_target?
135
+ false
136
+ end
137
+
138
+ def define_proxy_method(method)
139
+ metaclass = class << self; self; end
140
+ metaclass.class_eval do
141
+ define_proxy_method(method)
142
+ end
143
+ end
144
+
145
+ def define_and_call_proxy_method(method, *args, &block)
146
+ define_proxy_method(method)
147
+ public_send(method, *args, &block)
148
+ end
149
+
137
150
  def method_missing(method, *args, &block)
138
- if load_target
139
- target.send(method, *args, &block)
151
+ # load the target just in case it isn't loaded
152
+ load_target
153
+
154
+ # only define the method if the target has the method
155
+ # NOTE: include private methods!
156
+ if target.respond_to?(method, true)
157
+ define_and_call_proxy_method(method, *args, &block)
158
+ else
159
+ super
140
160
  end
141
161
  end
142
162
  end
@@ -8,20 +8,11 @@ module MongoMapper
8
8
 
9
9
  model.associations_module.module_eval(<<-end_eval, __FILE__, __LINE__ + 1)
10
10
  def #{name}
11
- proxy = get_proxy(associations[#{name.inspect}])
12
- proxy.nil? ? nil : proxy.read
11
+ get_proxy(associations[#{name.inspect}]).read
13
12
  end
14
13
 
15
14
  def #{name}=(value)
16
- association = associations[#{name.inspect}]
17
- proxy = get_proxy(association)
18
-
19
- if proxy.nil? || proxy.target != value
20
- proxy = build_proxy(association)
21
- end
22
-
23
- proxy.replace(value)
24
- proxy.read
15
+ get_proxy(associations[#{name.inspect}]).write(value)
25
16
  end
26
17
 
27
18
  def #{name}?
@@ -13,7 +13,7 @@ module MongoMapper
13
13
  end
14
14
  end
15
15
 
16
- def create_or_update(*)
16
+ def save_to_collection(*)
17
17
  super.tap do
18
18
  changes_applied
19
19
  end
@@ -38,7 +38,7 @@ module MongoMapper
38
38
 
39
39
  # typecast to the new value
40
40
  old_value = read_key(key_name)
41
- new_value = key.type.to_mongo(value)
41
+ new_value = key.set(value)
42
42
 
43
43
  # only mark changed if really changed value (after typecasting)
44
44
  unless old_value == new_value
@@ -46,7 +46,7 @@ module MongoMapper
46
46
  end
47
47
 
48
48
  def _root_document
49
- @_root_document ||= _parent_document.try(:_root_document)
49
+ _parent_document.try(:_root_document)
50
50
  end
51
51
  end
52
52
  end
@@ -61,7 +61,7 @@ module MongoMapper
61
61
  # Special Case: Generate default _id on access
62
62
  value = default_value if @is_id and !value
63
63
 
64
- value = type.from_mongo(value)
64
+ value = type ? type.from_mongo(value) : value
65
65
 
66
66
  if @typecast
67
67
  klass = typecast_class # Don't make this lookup on every call
@@ -76,22 +76,25 @@ module MongoMapper
76
76
 
77
77
  def set(value)
78
78
  # Avoid tap here so we don't have to create a block binding.
79
- values = type.to_mongo(value)
79
+ value = type ? type.to_mongo(value) : value.to_mongo
80
+
80
81
  if @typecast
81
- values.map { |v| typecast_class.to_mongo(v) }
82
+ klass = typecast_class # Don't make this lookup on every call
83
+ value.map { |v| klass.to_mongo(v) }
82
84
  else
83
- values
85
+ value
84
86
  end
85
87
  end
86
88
 
87
89
  def default_value
88
90
  return unless default?
91
+
89
92
  if default.instance_of? Proc
90
- type.to_mongo default.call
93
+ default.call
91
94
  else
92
95
  # Using Marshal is easiest way to get a copy of mutable objects
93
96
  # without getting an error on immutable objects
94
- type.to_mongo Marshal.load(Marshal.dump(default))
97
+ Marshal.load(Marshal.dump(default))
95
98
  end
96
99
  end
97
100
 
@@ -144,9 +144,8 @@ module MongoMapper
144
144
  end
145
145
 
146
146
  def create_accessors_for(key)
147
- accessors = ""
148
147
  if key.read_accessor?
149
- accessors << <<-end_eval
148
+ accessors_module.module_eval(<<-end_eval, __FILE__, __LINE__+1)
150
149
  def #{key.name}
151
150
  read_key(:#{key.name})
152
151
  end
@@ -158,7 +157,7 @@ module MongoMapper
158
157
  end
159
158
 
160
159
  if key.write_accessor?
161
- accessors << <<-end_eval
160
+ accessors_module.module_eval(<<-end_eval, __FILE__, __LINE__+1)
162
161
  def #{key.name}=(value)
163
162
  write_key(:#{key.name}, value)
164
163
  end
@@ -166,7 +165,7 @@ module MongoMapper
166
165
  end
167
166
 
168
167
  if key.predicate_accessor?
169
- accessors << <<-end_eval
168
+ accessors_module.module_eval(<<-end_eval, __FILE__, __LINE__+1)
170
169
  def #{key.name}?
171
170
  read_key(:#{key.name}).present?
172
171
  end
@@ -179,7 +178,6 @@ module MongoMapper
179
178
  end
180
179
  end
181
180
 
182
- accessors_module.module_eval accessors
183
181
  include accessors_module
184
182
  end
185
183
 
@@ -253,12 +251,24 @@ module MongoMapper
253
251
 
254
252
  def remove_validate_callbacks(a_name)
255
253
  chain = _validate_callbacks.dup.reject do |callback|
256
- f = callback.raw_filter
254
+ f = callback_filter(callback)
257
255
  f.respond_to?(:attributes) && f.attributes == a_name
258
256
  end
259
257
  reset_callbacks(:validate)
260
258
  chain.each do |callback|
261
- set_callback 'validate', callback.raw_filter
259
+ set_callback 'validate', callback_filter(callback)
260
+ end
261
+ end
262
+
263
+ # The interface to obtain @filter from ActiveSupport::Callbacks::Callback has changed since rails 7.0.
264
+ # https://github.com/rails/rails/commit/d5ac941ddc3de7ad1aaff80ed67aa04fb626a263#diff-bf79b7ea0085308139af6de0afad9a9f22f13d4563cc56d784994414d88c5dd1
265
+ if ActiveSupport::VERSION::MAJOR >= 7
266
+ def callback_filter(callback)
267
+ callback.filter
268
+ end
269
+ else
270
+ def callback_filter(callback)
271
+ callback.raw_filter
262
272
  end
263
273
  end
264
274
  end
@@ -148,7 +148,7 @@ module MongoMapper
148
148
  when :insert
149
149
  collection.insert_one(update, query_options)
150
150
  when :save
151
- collection.update_one({:_id => _id}, update, query_options.merge(upsert: true))
151
+ collection.update_one({:_id => _id}.merge(shard_key_filter), update, query_options.merge(upsert: true))
152
152
  when :update
153
153
  update.stringify_keys!
154
154
 
@@ -180,4 +180,4 @@ module MongoMapper
180
180
  end
181
181
  end
182
182
  end
183
- end
183
+ end