Skip to content

Commit

Permalink
Fix multi-level hash update w/o nested attributes. Fixes #1936.
Browse files Browse the repository at this point in the history
  • Loading branch information
durran committed May 5, 2012
1 parent 8797e28 commit dec16ac
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,10 @@ For instructions on upgrading to newer versions, visit

### Resolved Issues

* \#1936 Allow setting n levels deep embedded documents atomically without
conflicting mods when not using nested attributes or documents themselves
in an update call from the parent.

* \#1957/\#1954 Ensure database name is set with inheritance.
(Hans Hasselberg)

Expand Down
3 changes: 3 additions & 0 deletions lib/mongoid/atomic.rb
Expand Up @@ -252,6 +252,9 @@ def delayed_atomic_pulls
# @example Get the atomic paths.
# document.atomic_paths
#
# @todo: Durran: Should probably raise error for embedded docs w/o
# metadata.
#
# @return [ Object ] The associated path.
#
# @since 2.1.0
Expand Down
10 changes: 9 additions & 1 deletion lib/mongoid/relations/embedded/many.rb
Expand Up @@ -307,7 +307,11 @@ def substitute(replacement)
atomically(:$set) do
base.delayed_atomic_sets.clear
if replacement.first.is_a?(Hash)
replacement = Many.builder(base, metadata, replacement).build
replacement = replacement.map do |doc|
attributes = { metadata: metadata, _parent: base }
attributes.merge!(doc)
Factory.build(klass, attributes)
end
end
docs = replacement.compact
proxy.target = docs
Expand All @@ -319,6 +323,10 @@ def substitute(replacement)
end
if _assigning?
name = _unscoped.first.atomic_path
base._children.each do |child|
child.delayed_atomic_sets.clear
end
base.instance_variable_set(:@_children, nil)
base.delayed_atomic_sets[name] = proxy.as_document
end
end
Expand Down
49 changes: 49 additions & 0 deletions spec/functional/mongoid/relations/embedded/many_spec.rb
Expand Up @@ -3025,4 +3025,53 @@
end
end
end

context "when adding a document" do

let(:person) do
Person.new
end

let(:address_one) do
Address.new(street: "hobrecht")
end

let(:first_add) do
person.addresses.push(address_one)
end
end

context "when updating multiple levels in one update" do

let!(:person) do
Person.create(
addresses: [
{ locations: [{ name: "home" }]}
]
)
end

context "when updating with hashes" do

let(:from_db) do
Person.find(person.id)
end

before do
from_db.update_attributes(
addresses: [
{ locations: [{ name: "work" }]}
]
)
end

let(:updated) do
person.reload.addresses.first.locations.first
end

it "updates the nested document" do
updated.name.should eq("work")
end
end
end
end

0 comments on commit dec16ac

Please sign in to comment.