Skip to content

Commit

Permalink
Allow embedded arrays to properly get updated atomically. Fixes #1593
Browse files Browse the repository at this point in the history
  • Loading branch information
durran committed Jan 15, 2012
1 parent 6ff71c1 commit 72fb250
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -47,6 +47,9 @@ For instructions on upgrading to newer versions, visit

### Resolved Issues

* \#1593 Arrays on embedded documents now properly atomically update when
modified from original version.

* \#1592 Don't swallow exceptions from index generation in the create_indexes
rake task.

Expand Down
9 changes: 8 additions & 1 deletion lib/mongoid/dirty.rb
Expand Up @@ -131,7 +131,14 @@ def setters
field = fields[name]
key = embedded? ? "#{atomic_position}.#{name}" : name
if field && field.resizable?
field.add_atomic_changes(self, key, modifications, new, old)
field.add_atomic_changes(
self,
name,
key,
modifications,
new,
old
)
else
modifications[key] = new
end
Expand Down
7 changes: 4 additions & 3 deletions lib/mongoid/fields/internal/array.rb
Expand Up @@ -13,19 +13,20 @@ class Array
# field.add_atomic_changes(doc, "key", {}, [], [])
#
# @param [ Document ] document The document to add to.
# @param [ String ] key The name of the field.
# @param [ String ] name The name of the field.
# @param [ String ] key The atomic location of the field.
# @param [ Hash ] mods The current modifications.
# @param [ Array ] new The new elements to add.
# @param [ Array ] old The old elements getting removed.
#
# @since 2.4.0
def add_atomic_changes(document, key, mods, new, old)
def add_atomic_changes(document, name, key, mods, new, old)
pushes = (new || []) - (old || [])
pulls = (old || []) - (new || [])
if old.nil?
mods[key] = pushes
elsif !pushes.empty? && !pulls.empty?
mods[key] = document.attributes[key]
mods[key] = document.attributes[name]
elsif !pushes.empty?
document.atomic_array_pushes[key] = pushes
elsif !pulls.empty?
Expand Down
7 changes: 4 additions & 3 deletions lib/mongoid/fields/internal/foreign_keys/array.rb
Expand Up @@ -14,19 +14,20 @@ class Array
# field.add_atomic_changes(doc, "key", {}, [], [])
#
# @param [ Document ] document The document to add to.
# @param [ String ] key The name of the field.
# @param [ String ] name The name of the field.
# @param [ String ] key The atomic location of the field.
# @param [ Hash ] mods The current modifications.
# @param [ Array ] new The new elements to add.
# @param [ Array ] old The old elements getting removed.
#
# @since 2.4.0
def add_atomic_changes(document, key, mods, new, old)
def add_atomic_changes(document, name, key, mods, new, old)
pushes = (new || []) - (old || [])
pulls = (old || []) - (new || [])
if old.nil?
mods[key] = pushes
elsif !pushes.empty? && !pulls.empty?
mods[key] = document.attributes[key]
mods[key] = document.attributes[name]
elsif !pushes.empty?
document.atomic_array_add_to_sets[key] = pushes
elsif !pulls.empty?
Expand Down
1 change: 1 addition & 0 deletions spec/app/models/video.rb
Expand Up @@ -3,6 +3,7 @@ class Video
field :title, :type => String
field :year, :type => Integer
field :release_dates, :type => Set
field :genres, :type => Array

embedded_in :person
belongs_to :post
Expand Down
54 changes: 54 additions & 0 deletions spec/functional/mongoid/relations/embedded/many_spec.rb
Expand Up @@ -2686,4 +2686,58 @@
end
end
end

context "when the embedded document has an array field" do

let!(:person) do
Person.create(:ssn => "673-11-2322")
end

let!(:video) do
person.videos.create
end

context "when saving the array on a persisted document" do

before do
video.genres = [ "horror", "scifi" ]
video.save
end

it "sets the value" do
video.genres.should eq([ "horror", "scifi" ])
end

it "persists the value" do
video.reload.genres.should eq([ "horror", "scifi" ])
end

context "when reloading the parent" do

let!(:loaded_person) do
Person.find(person.id)
end

let!(:loaded_video) do
loaded_person.videos.find(video.id)
end

context "when writing a new array value" do

before do
loaded_video.genres = [ "comedy" ]
loaded_video.save
end

it "sets the new value" do
loaded_video.genres.should eq([ "comedy" ])
end

it "persists the new value" do
loaded_video.reload.genres.should eq([ "comedy" ])
end
end
end
end
end
end
4 changes: 2 additions & 2 deletions spec/unit/mongoid/fields/internal/array_spec.rb
Expand Up @@ -23,7 +23,7 @@
before do
person.aliases = [ "007", "008" ]
field.add_atomic_changes(
person, "aliases", mods, [ "008" ], [ "009" ]
person, "aliases", "aliases", mods, [ "008" ], [ "009" ]
)
end

Expand All @@ -37,7 +37,7 @@
before do
person.aliases = [ "007", nil ]
field.add_atomic_changes(
person, "aliases", mods, [ nil ], [ "008" ]
person, "aliases", "aliases", mods, [ nil ], [ "008" ]
)
end

Expand Down
Expand Up @@ -42,7 +42,7 @@

before do
field.add_atomic_changes(
person, "preference_ids", mods, [ preference_three.id ], [ preference_two.id ]
person, "preference_ids", "preference_ids", mods, [ preference_three.id ], [ preference_two.id ]
)
end

Expand Down

0 comments on commit 72fb250

Please sign in to comment.