mongoid 8.1.5 → 8.1.6

Sign up to get free protection for your applications and to get access to all the features.
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