mongoid 8.1.5 → 8.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +44 -46
  3. data/lib/mongoid/association/accessors.rb +5 -1
  4. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -1
  5. data/lib/mongoid/extensions/hash.rb +4 -4
  6. data/lib/mongoid/fields.rb +13 -8
  7. data/lib/mongoid/touchable.rb +1 -1
  8. data/lib/mongoid/version.rb +1 -1
  9. data/spec/integration/app_spec.rb +3 -2
  10. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
  11. data/spec/mongoid/attributes_spec.rb +16 -0
  12. data/spec/mongoid/contextual/mongo_spec.rb +72 -3
  13. data/spec/mongoid/fields_spec.rb +3 -3
  14. data/spec/mongoid/serializable_spec.rb +16 -9
  15. data/spec/support/models/band.rb +1 -0
  16. data/spec/support/models/lat_lng.rb +6 -0
  17. metadata +9 -82
  18. checksums.yaml.gz.sig +0 -0
  19. data/spec/shared/LICENSE +0 -20
  20. data/spec/shared/bin/get-mongodb-download-url +0 -17
  21. data/spec/shared/bin/s3-copy +0 -45
  22. data/spec/shared/bin/s3-upload +0 -69
  23. data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
  24. data/spec/shared/lib/mrss/cluster_config.rb +0 -231
  25. data/spec/shared/lib/mrss/constraints.rb +0 -378
  26. data/spec/shared/lib/mrss/docker_runner.rb +0 -298
  27. data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
  28. data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
  29. data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
  30. data/spec/shared/lib/mrss/server_version_registry.rb +0 -113
  31. data/spec/shared/lib/mrss/session_registry.rb +0 -69
  32. data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
  33. data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
  34. data/spec/shared/lib/mrss/utils.rb +0 -37
  35. data/spec/shared/share/Dockerfile.erb +0 -321
  36. data/spec/shared/share/haproxy-1.conf +0 -16
  37. data/spec/shared/share/haproxy-2.conf +0 -17
  38. data/spec/shared/shlib/config.sh +0 -27
  39. data/spec/shared/shlib/distro.sh +0 -74
  40. data/spec/shared/shlib/server.sh +0 -416
  41. data/spec/shared/shlib/set_env.sh +0 -169
  42. data.tar.gz.sig +0 -0
  43. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dbe9ca12b60eeee360717af6f05117691a514c4b37f645c456b7c2675ab60606
4
- data.tar.gz: 145e999e0a17a6eff2d19c7188a2aee7f27785308f507cd57df1d8ac74ebe93d
3
+ metadata.gz: f4218c578b31195178d4f2425bf42c70741f23e123832c9dcc0df9794b1bfbaa
4
+ data.tar.gz: 24b7b07e571fff97c9c35cc4f2477f6def8202211a35fb205711f73492f8f68c
5
5
  SHA512:
6
- metadata.gz: bb5249dd2e2eea2d2ba3fdfa2c84c3dbaa71b181e22ff2a181854ce029499cf723487b00ec4ad4eef0619fda4bfcf3b071f36dc436ef46321fcf7c99319124d4
7
- data.tar.gz: 1ff5ba0852368f7f032c80e18bcfd27934ee35a3e91e84197e6641f0d966b914c29c5aac8cd4e81df720db2b8b8bd54c42fc25e9b2c8a9e8cf1fb33f9da8cc89
6
+ metadata.gz: 4086af26408203774f2c4861ae84707adea2dd45fff821470a9517e9ec10c41fc4c80a3e566a25118806e2d89311f6eb1aa8a9e27953ba5784cb22d78025e0ea
7
+ data.tar.gz: 1b50e4fff002cc80175aa6c8e489f79c37f5b2cfebdf9adfe6da316b38bab18540a96717d7f217ed2054f7022faf4ec9eb42129e0474b59d3266c3585d237184
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler"
4
- require "bundler/gem_tasks"
5
4
  Bundler.setup
6
5
 
7
6
  ROOT = File.expand_path(File.join(File.dirname(__FILE__)))
@@ -10,34 +9,53 @@ $: << File.join(ROOT, 'spec/shared/lib')
10
9
 
11
10
  require "rake"
12
11
  require "rspec/core/rake_task"
13
- require 'mrss/spec_organizer'
14
- require 'rubygems/package'
15
- require 'rubygems/security/policies'
16
-
17
- def signed_gem?(path_to_gem)
18
- Gem::Package.new(path_to_gem, Gem::Security::HighSecurity).verify
19
- true
20
- rescue Gem::Security::Exception => e
21
- false
22
- end
23
-
24
- $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
25
- require "mongoid/version"
26
-
27
- tasks = Rake.application.instance_variable_get('@tasks')
28
- tasks['release:do'] = tasks.delete('release')
29
12
 
30
- task :gem => :build
13
+ # stands in for the Bundler-provided `build` task, which builds the
14
+ # gem for this project. Our release process builds the gems in a
15
+ # particular way, in a GitHub action. This task is just to help remind
16
+ # developers of that fact.
31
17
  task :build do
32
- system "gem build mongoid.gemspec"
18
+ abort <<~WARNING
19
+ `rake build` does nothing in this project. The gem must be built via
20
+ the `Mongoid Release` action on GitHub, which is triggered manually when
21
+ a new release is ready.
22
+ WARNING
33
23
  end
34
24
 
35
- task :install => :build do
36
- system "sudo gem install mongoid-#{Mongoid::VERSION}.gem"
25
+ # `rake version` is used by the deployment system so get the release version
26
+ # of the product beng deployed. It must do nothing more than just print the
27
+ # product version number.
28
+ #
29
+ # See the mongodb-labs/driver-github-tools/ruby/publish Github action.
30
+ desc "Print the current value of Mongoid::VERSION"
31
+ task :version do
32
+ require 'mongoid/version'
33
+
34
+ puts Mongoid::VERSION
37
35
  end
38
36
 
37
+ # overrides the default Bundler-provided `release` task, which also
38
+ # builds the gem. Our release process assumes the gem has already
39
+ # been built (and signed via GPG), so we just need `rake release` to
40
+ # push the gem to rubygems.
39
41
  task :release do
40
- raise "Please use ./release.sh to release"
42
+ require 'mongoid/version'
43
+
44
+ if ENV['GITHUB_ACTION'].nil?
45
+ abort <<~WARNING
46
+ `rake release` must be invoked from the `Mongoid Release` GitHub action,
47
+ and must not be invoked locally. This ensures the gem is properly signed
48
+ and distributed by the appropriate user.
49
+
50
+ Note that it is the `rubygems/release-gem@v1` step in the `Mongoid Release`
51
+ action that invokes this task. Do not rename or remove this task, or the
52
+ release-gem step will fail. Reimplement this task with caution.
53
+
54
+ mongoid-#{Mongoid::VERSION}.gem was NOT pushed to RubyGems.
55
+ WARNING
56
+ end
57
+
58
+ system 'gem', 'push', "mongoid-#{Mongoid::VERSION}.gem"
41
59
  end
42
60
 
43
61
  RSpec::Core::RakeTask.new("spec") do |spec|
@@ -64,6 +82,8 @@ RUN_PRIORITY = %i(
64
82
  )
65
83
 
66
84
  def spec_organizer
85
+ require 'mrss/spec_organizer'
86
+
67
87
  Mrss::SpecOrganizer.new(
68
88
  root: ROOT,
69
89
  classifiers: CLASSIFIERS,
@@ -99,32 +119,10 @@ task :docs => 'docs:yard'
99
119
  namespace :docs do
100
120
  desc "Generate yard documention"
101
121
  task :yard do
122
+ require "mongoid/version"
123
+
102
124
  out = File.join('yard-docs', Mongoid::VERSION)
103
125
  FileUtils.rm_rf(out)
104
126
  system "yardoc -o #{out} --title mongoid-#{Mongoid::VERSION}"
105
127
  end
106
128
  end
107
-
108
- namespace :release do
109
- task :check_private_key do
110
- unless File.exist?('gem-private_key.pem')
111
- raise "No private key present, cannot release"
112
- end
113
- end
114
- end
115
-
116
- desc 'Verifies that all built gems in pkg/ are valid'
117
- task :verify do
118
- gems = Dir['pkg/*.gem']
119
- if gems.empty?
120
- puts 'There are no gems in pkg/ to verify'
121
- else
122
- gems.each do |gem|
123
- if signed_gem?(gem)
124
- puts "#{gem} is signed"
125
- else
126
- abort "#{gem} is not signed"
127
- end
128
- end
129
- end
130
- end
@@ -115,7 +115,11 @@ module Mongoid
115
115
  # during binding or when cascading callbacks. Whenever we retrieve
116
116
  # associations within the codebase, we use without_autobuild.
117
117
  if !without_autobuild? && association.embedded? && attribute_missing?(field_name)
118
- raise ActiveModel::MissingAttributeError, "Missing attribute: '#{field_name}'"
118
+ # We always allow accessing the parent document of an embedded one.
119
+ try_get_parent = association.is_a?(
120
+ Mongoid::Association::Embedded::EmbeddedIn
121
+ ) && field_name == association.key
122
+ raise ActiveModel::MissingAttributeError, "Missing attribute: '#{field_name}'" unless try_get_parent
119
123
  end
120
124
 
121
125
  if !reload && (value = ivar(name)) != false
@@ -43,7 +43,21 @@ module Mongoid
43
43
  #
44
44
  # @return [ Object ] The converted number.
45
45
  def __numeric__(object)
46
- object.to_s.match?(/\A[-+]?[0-9]*[0-9.]0*\z/) ? object.to_i : Float(object)
46
+ str = object.to_s
47
+ raise ArgumentError if str.empty?
48
+
49
+ # These requirements seem a bit odd, but they're explicitly specified in the tests,
50
+ # so we're obligated to keep them, for now. (This code was rewritten from a one-line
51
+ # regex, due to security concerns with a polynomial regex being used on uncontrolled
52
+ # data).
53
+
54
+ str = str.chop if str.end_with?('.')
55
+ return 0 if str.empty?
56
+
57
+ result = Integer(str) rescue Float(object)
58
+
59
+ integer = result.to_i
60
+ integer == result ? integer : result
47
61
  end
48
62
 
49
63
  # Evolve the object to an integer.
@@ -49,7 +49,7 @@ module Mongoid
49
49
  consolidated[key].update(value)
50
50
  else
51
51
  consolidated["$set"] ||= {}
52
- consolidated["$set"].update(key => mongoize_for(key, klass, key, value))
52
+ consolidated["$set"].update(key => mongoize_for("$set", klass, key, value))
53
53
  end
54
54
  end
55
55
  consolidated
@@ -187,7 +187,7 @@ module Mongoid
187
187
 
188
188
  # Get the value for the provided operator, klass, key and value.
189
189
  #
190
- # This is necessary for special cases like $rename, $addToSet and $push.
190
+ # This is necessary for special cases like $rename, $addToSet, $push, $pull and $pop.
191
191
  #
192
192
  # @param [ String ] operator The operator.
193
193
  # @param [ Class ] klass The model class.
@@ -198,8 +198,8 @@ module Mongoid
198
198
  def value_for(operator, klass, key, value)
199
199
  case operator
200
200
  when "$rename" then value.to_s
201
- when "$addToSet", "$push" then value.mongoize
202
- else mongoize_for(operator, klass, operator, value)
201
+ when "$addToSet", "$push", '$pull', '$pop' then value.mongoize
202
+ else mongoize_for(operator, klass, key, value)
203
203
  end
204
204
  end
205
205
 
@@ -47,6 +47,11 @@ module Mongoid
47
47
  # @api private
48
48
  INVALID_BSON_CLASSES = [ BSON::Decimal128, BSON::Int32, BSON::Int64 ].freeze
49
49
 
50
+ # The suffix for generated translated fields.
51
+ #
52
+ # @api private
53
+ TRANSLATIONS_SFX = '_translations'
54
+
50
55
  module ClassMethods
51
56
  # Returns the list of id fields for this model class, as both strings
52
57
  # and symbols.
@@ -99,8 +104,8 @@ module Mongoid
99
104
  ar.each_with_index do |fn, i|
100
105
  key = fn
101
106
  unless klass.fields.key?(fn) || klass.relations.key?(fn)
102
- if tr = fn.match(/(.*)_translations\z/)&.captures&.first
103
- key = tr
107
+ if fn.end_with?(TRANSLATIONS_SFX)
108
+ key = fn.delete_suffix(TRANSLATIONS_SFX)
104
109
  else
105
110
  key = fn
106
111
  end
@@ -405,12 +410,12 @@ module Mongoid
405
410
  #
406
411
  # @api private
407
412
  def database_field_name(name, relations, aliased_fields, aliased_associations)
413
+ return '' unless name.present?
414
+
408
415
  if Mongoid.broken_alias_handling
409
- return nil unless name
410
416
  normalized = name.to_s
411
417
  aliased_fields[normalized] || normalized
412
418
  else
413
- return nil unless name.present?
414
419
  key = name.to_s
415
420
  segment, remaining = key.split('.', 2)
416
421
 
@@ -726,11 +731,11 @@ module Mongoid
726
731
  # @api private
727
732
  def create_translations_getter(name, meth)
728
733
  generated_methods.module_eval do
729
- re_define_method("#{meth}_translations") do
734
+ re_define_method("#{meth}#{TRANSLATIONS_SFX}") do
730
735
  attributes[name] ||= {}
731
736
  attributes[name].with_indifferent_access
732
737
  end
733
- alias_method :"#{meth}_t", :"#{meth}_translations"
738
+ alias_method :"#{meth}_t", :"#{meth}#{TRANSLATIONS_SFX}"
734
739
  end
735
740
  end
736
741
 
@@ -746,14 +751,14 @@ module Mongoid
746
751
  # @api private
747
752
  def create_translations_setter(name, meth, field)
748
753
  generated_methods.module_eval do
749
- re_define_method("#{meth}_translations=") do |value|
754
+ re_define_method("#{meth}#{TRANSLATIONS_SFX}=") do |value|
750
755
  attribute_will_change!(name)
751
756
  value&.transform_values! do |_value|
752
757
  field.type.mongoize(_value)
753
758
  end
754
759
  attributes[name] = value
755
760
  end
756
- alias_method :"#{meth}_t=", :"#{meth}_translations="
761
+ alias_method :"#{meth}_t=", :"#{meth}#{TRANSLATIONS_SFX}="
757
762
  end
758
763
  end
759
764
 
@@ -25,7 +25,7 @@ module Mongoid
25
25
  current = Time.configured.now
26
26
  field = database_field_name(field)
27
27
  write_attribute(:updated_at, current) if respond_to?("updated_at=")
28
- write_attribute(field, current) if field
28
+ write_attribute(field, current) if field.present?
29
29
 
30
30
  # If the document being touched is embedded, touch its parents
31
31
  # all the way through the composition hierarchy to the root object,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mongoid
4
- VERSION = "8.1.5"
4
+ VERSION = "8.1.6"
5
5
  end
@@ -205,7 +205,7 @@ describe 'Mongoid application tests' do
205
205
  FileUtils.rm_rf(File.basename(repo_url))
206
206
  check_call(%w(git clone) + [repo_url])
207
207
  Dir.chdir(File.join(*[File.basename(repo_url), subdir].compact)) do
208
- adjust_app_gemfile
208
+ adjust_app_gemfile(add_sprockets: false)
209
209
  adjust_rails_defaults
210
210
  check_call(%w(bundle install), env: clean_env)
211
211
  puts `git diff`
@@ -262,7 +262,7 @@ describe 'Mongoid application tests' do
262
262
  end
263
263
  end
264
264
 
265
- def adjust_app_gemfile(rails_version: SpecConfig.instance.rails_version)
265
+ def adjust_app_gemfile(rails_version: SpecConfig.instance.rails_version, add_sprockets: true)
266
266
  remove_bundler_req
267
267
 
268
268
  gemfile_lines = IO.readlines('Gemfile')
@@ -280,6 +280,7 @@ describe 'Mongoid application tests' do
280
280
  gemfile_lines << "gem 'rails', '~> #{rails_version}.0'\n"
281
281
  end
282
282
  end
283
+ gemfile_lines << "gem 'sprockets-rails'\n" if add_sprockets
283
284
  File.open('Gemfile', 'w') do |f|
284
285
  f << gemfile_lines.join
285
286
  end
@@ -27,6 +27,10 @@ describe Mongoid::Association::Embedded::EmbedsMany do
27
27
  expect(legislator.attributes.keys).to eq(['_id', 'a'])
28
28
  end
29
29
 
30
+ it 'allows accessing the parent' do
31
+ expect { legislator.congress }.not_to raise_error
32
+ end
33
+
30
34
  context 'when using only with $' do
31
35
  before do
32
36
  Patient.destroy_all
@@ -288,6 +288,22 @@ describe Mongoid::Attributes do
288
288
  end
289
289
  end
290
290
 
291
+ context "when given nil" do
292
+
293
+ it "returns nil" do
294
+ expect(person[nil]).to be nil
295
+ end
296
+
297
+ end
298
+
299
+ context "when given an empty string" do
300
+
301
+ it "returns nil" do
302
+ expect(person[""]).to be nil
303
+ end
304
+
305
+ end
306
+
291
307
  context "when the field was not explicitly defined" do
292
308
 
293
309
  context "when excluding with only and the field was not excluded" do
@@ -3746,6 +3746,75 @@ describe Mongoid::Contextual::Mongo do
3746
3746
  expect(new_order.reload.genres).to eq(["electronic"])
3747
3747
  end
3748
3748
  end
3749
+
3750
+ context "when operation is $pull" do
3751
+ context "when pulling single element" do
3752
+
3753
+ before do
3754
+ depeche_mode.update_attribute(:genres, ["electronic", "pop"])
3755
+ new_order.update_attribute(:genres, ["electronic", "pop"])
3756
+ context.update_all("$pull" => { genres: "electronic" })
3757
+ end
3758
+
3759
+ it "updates the first matching document" do
3760
+ expect(depeche_mode.reload.genres).to eq(["pop"])
3761
+ end
3762
+
3763
+ it "updates the last matching document" do
3764
+ expect(new_order.reload.genres).to eq(["pop"])
3765
+ end
3766
+ end
3767
+
3768
+ context "when pulling based on condition" do
3769
+ before do
3770
+ depeche_mode.update_attribute(:genres, ["electronic", "pop", "dance"])
3771
+ new_order.update_attribute(:genres, ["electronic", "pop", "dance"])
3772
+ context.update_all("$pull" => { genres: { '$in' => ["electronic", "pop"] } })
3773
+ end
3774
+
3775
+ it "updates the first matching document" do
3776
+ expect(depeche_mode.reload.genres).to eq(["dance"])
3777
+ end
3778
+
3779
+ it "updates the last matching document" do
3780
+ expect(new_order.reload.genres).to eq(["dance"])
3781
+ end
3782
+ end
3783
+ end
3784
+
3785
+ context "when operation is $pop" do
3786
+
3787
+ before do
3788
+ depeche_mode.update_attribute(:genres, ["pop", "electronic"])
3789
+ end
3790
+
3791
+ it "removes first element in array" do
3792
+ context.update_all("$pop" => { genres: -1 })
3793
+ expect(depeche_mode.reload.genres).to eq(["electronic"])
3794
+ end
3795
+
3796
+ it "removes last element in array" do
3797
+ context.update_all("$pop" => { genres: 1 })
3798
+ expect(depeche_mode.reload.genres).to eq(["pop"])
3799
+ end
3800
+ end
3801
+
3802
+ context "when operation is $pullAll" do
3803
+
3804
+ before do
3805
+ depeche_mode.update_attribute(:genres, ["pop", "electronic", "dance", "pop" ])
3806
+ new_order.update_attribute(:genres, ["electronic", "pop", "electronic", "dance"])
3807
+ context.update_all("$pullAll" => { genres: ["pop", "electronic"] })
3808
+ end
3809
+
3810
+ it "updates the first matching document" do
3811
+ expect(depeche_mode.reload.genres).to eq(["dance"])
3812
+ end
3813
+
3814
+ it "updates the last matching document" do
3815
+ expect(new_order.reload.genres).to eq(["dance"])
3816
+ end
3817
+ end
3749
3818
  end
3750
3819
 
3751
3820
  context 'when using aliased field names' do
@@ -3765,15 +3834,15 @@ describe Mongoid::Contextual::Mongo do
3765
3834
  context "when the attributes must be mongoized" do
3766
3835
 
3767
3836
  before do
3768
- context.update_all("$set" => { member_count: "1" })
3837
+ context.update_all("$set" => { location: LatLng.new(52.30, 13.25) })
3769
3838
  end
3770
3839
 
3771
3840
  it "updates the first matching document" do
3772
- expect(depeche_mode.reload.member_count).to eq(1)
3841
+ expect(depeche_mode.reload.location).to eq(LatLng.new(52.30, 13.25))
3773
3842
  end
3774
3843
 
3775
3844
  it "updates the last matching document" do
3776
- expect(new_order.reload.member_count).to eq(1)
3845
+ expect(new_order.reload.location).to eq(LatLng.new(52.30, 13.25))
3777
3846
  end
3778
3847
  end
3779
3848
  end
@@ -1845,12 +1845,12 @@ describe Mongoid::Fields do
1845
1845
 
1846
1846
  context 'given nil' do
1847
1847
  subject { Person.database_field_name(nil) }
1848
- it { is_expected.to eq nil }
1848
+ it { is_expected.to eq '' }
1849
1849
  end
1850
1850
 
1851
1851
  context 'given an empty String' do
1852
1852
  subject { Person.database_field_name('') }
1853
- it { is_expected.to eq nil }
1853
+ it { is_expected.to eq '' }
1854
1854
  end
1855
1855
 
1856
1856
  context 'given a String' do
@@ -1869,7 +1869,7 @@ describe Mongoid::Fields do
1869
1869
 
1870
1870
  context 'given nil' do
1871
1871
  subject { Person.database_field_name(nil) }
1872
- it { is_expected.to eq nil }
1872
+ it { is_expected.to eq '' }
1873
1873
  end
1874
1874
 
1875
1875
  context 'given an empty String' do
@@ -510,13 +510,15 @@ describe Mongoid::Serializable do
510
510
  end
511
511
 
512
512
  it "includes the first relation" do
513
- expect(relation_hash[0]).to include
513
+ expect(relation_hash[0]).to include(
514
514
  { "_id" => "kudamm", "street" => "Kudamm" }
515
+ )
515
516
  end
516
517
 
517
518
  it "includes the second relation" do
518
- expect(relation_hash[1]).to include
519
+ expect(relation_hash[1]).to include(
519
520
  { "_id" => "tauentzienstr", "street" => "Tauentzienstr" }
521
+ )
520
522
  end
521
523
  end
522
524
 
@@ -527,13 +529,15 @@ describe Mongoid::Serializable do
527
529
  end
528
530
 
529
531
  it "includes the first relation" do
530
- expect(relation_hash[0]).to include
532
+ expect(relation_hash[0]).to include(
531
533
  { "_id" => "kudamm", "street" => "Kudamm" }
534
+ )
532
535
  end
533
536
 
534
537
  it "includes the second relation" do
535
- expect(relation_hash[1]).to include
538
+ expect(relation_hash[1]).to include(
536
539
  { "_id" => "tauentzienstr", "street" => "Tauentzienstr" }
540
+ )
537
541
  end
538
542
  end
539
543
 
@@ -652,8 +656,9 @@ describe Mongoid::Serializable do
652
656
  end
653
657
 
654
658
  it "includes the specified relation" do
655
- expect(relation_hash).to include
656
- { "_id" => "leo-marvin", "first_name" => "Leo", "last_name" => "Marvin" }
659
+ expect(relation_hash).to include(
660
+ { "_id" => "Leo-Marvin", "first_name" => "Leo", "last_name" => "Marvin" }
661
+ )
657
662
  end
658
663
  end
659
664
 
@@ -664,8 +669,9 @@ describe Mongoid::Serializable do
664
669
  end
665
670
 
666
671
  it "includes the specified relation" do
667
- expect(relation_hash).to include
668
- { "_id" => "leo-marvin", "first_name" => "Leo", "last_name" => "Marvin" }
672
+ expect(relation_hash).to include(
673
+ { "_id" => "Leo-Marvin", "first_name" => "Leo", "last_name" => "Marvin" }
674
+ )
669
675
  end
670
676
  end
671
677
 
@@ -676,8 +682,9 @@ describe Mongoid::Serializable do
676
682
  end
677
683
 
678
684
  it "includes the specified relation sans exceptions" do
679
- expect(relation_hash).to include
685
+ expect(relation_hash).to include(
680
686
  { "first_name" => "Leo", "last_name" => "Marvin" }
687
+ )
681
688
  end
682
689
  end
683
690
  end
@@ -23,6 +23,7 @@ class Band
23
23
  field :mojo, type: Object
24
24
  field :tags, type: Hash
25
25
  field :fans
26
+ field :location, type: LatLng
26
27
 
27
28
  embeds_many :records, cascade_callbacks: true
28
29
  embeds_many :notes, as: :noteable, cascade_callbacks: true, validate: false
@@ -4,6 +4,8 @@ class LatLng
4
4
  attr_accessor :lat, :lng
5
5
 
6
6
  def self.demongoize(object)
7
+ return if object.nil?
8
+
7
9
  LatLng.new(object[1], object[0])
8
10
  end
9
11
 
@@ -14,4 +16,8 @@ class LatLng
14
16
  def mongoize
15
17
  [ lng, lat ]
16
18
  end
19
+
20
+ def ==(other)
21
+ lat == other.lat && lng == other.lng
22
+ end
17
23
  end