Skip to content

Commit

Permalink
MONGOID-5624 Fix alias issue when store_as is different case (#5675)
Browse files Browse the repository at this point in the history
* trying a fix for aliased field names

* add a test case for bug

* remove to_s

* Remove _ids aliases

* Revert "Remove _ids aliases"

This reverts commit 24b9e67.

* Add stored_as_associations

* Cleanup

* Fix code review remarks

---------

Co-authored-by: Dmitry Rybakov <dmitry.rybakov@mongodb.com>
  • Loading branch information
alexbeeken and comandeo-mongo committed Aug 17, 2023
1 parent be61226 commit cb9b8f3
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 5 deletions.
6 changes: 6 additions & 0 deletions lib/mongoid/association/macros.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,15 @@ module Macros
# @api private
class_attribute :aliased_associations

# @return [ Set<String> ] The set of associations that are configured
# with :store_as parameter.
class_attribute :stored_as_associations

self.embedded = false
self.embedded_relations = BSON::Document.new
self.relations = BSON::Document.new
self.aliased_associations = {}
self.stored_as_associations = Set.new
end

# This is convenience for libraries still on the old API.
Expand Down Expand Up @@ -219,6 +224,7 @@ def define_association!(macro_name, name, options = {}, &block)
self.relations = self.relations.merge(name => assoc)
if assoc.embedded? && assoc.respond_to?(:store_as) && assoc.store_as != name
self.aliased_associations[assoc.store_as] = name
self.stored_as_associations << assoc.store_as
end
end
end
Expand Down
34 changes: 29 additions & 5 deletions lib/mongoid/attributes/processing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,46 @@ def process_attributes(attrs = nil)
# @return [ true | false ] True if pending, false if not.
def pending_attribute?(key, value)
name = key.to_s

aliased = if aliased_associations.key?(name)
aliased_associations[name]
else
name
end

if relations.has_key?(aliased)
pending_relations[name] = value
set_pending_relation(name, aliased, value)
return true
end
if nested_attributes.has_key?(aliased)
pending_nested[name] = value
set_pending_nested(name, aliased, value)
return true
end
return false
false
end

# Set value of the pending relation.
#
# @param [ Symbol ] name The name of the relation.
# @param [ Symbol ] aliased The aliased name of the relation.
# @param [ Object ] value The value of the relation.
def set_pending_relation(name, aliased, value)
if stored_as_associations.include?(name)
pending_relations[aliased] = value
else
pending_relations[name] = value
end
end

# Set value of the pending nested attribute.
#
# @param [ Symbol ] name The name of the nested attribute.
# @param [ Symbol ] aliased The aliased name of the nested attribute.
# @param [ Object ] value The value of the nested attribute.
def set_pending_nested(name, aliased, value)
if stored_as_associations.include?(name)
pending_nested[aliased] = value
else
pending_nested[name] = value
end
end

# Get all the pending associations that need to be set.
Expand Down
27 changes: 27 additions & 0 deletions spec/mongoid/attributes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2711,4 +2711,31 @@
catalog.set_field.should == Set.new([ 1, 2 ])
end
end

context 'when an embedded field has a capitalized store_as name' do
let(:person) { Person.new(Purse: { brand: 'Gucci' }) }

it 'sets the value' do
expect(person.purse.brand).to eq('Gucci')
end

it 'saves successfully' do
expect(person.save!).to eq(true)
end

context 'when persisted' do
before do
person.save!
person.reload
end

it 'persists the value' do
expect(person.reload.purse.brand).to eq('Gucci')
end

it 'uses the correct key in the database' do
expect(person.collection.find(_id: person.id).first['Purse']['_id']).to eq(person.purse.id)
end
end
end
end
1 change: 1 addition & 0 deletions spec/support/models/person.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def find_by_street(street)
embeds_many :messages, validate: false

embeds_one :passport, autobuild: true, store_as: :pass, validate: false
embeds_one :purse, store_as: "Purse"
embeds_one :pet, class_name: "Animal", validate: false
embeds_one :name, as: :namable, validate: false do
def extension
Expand Down
9 changes: 9 additions & 0 deletions spec/support/models/purse.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class Purse
include Mongoid::Document

field :brand, type: String

embedded_in :person
end

0 comments on commit cb9b8f3

Please sign in to comment.