diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eba9d4ad9..a4784bbec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/lib/mongoid/dirty.rb b/lib/mongoid/dirty.rb index 7e1b684980..54d554cf73 100644 --- a/lib/mongoid/dirty.rb +++ b/lib/mongoid/dirty.rb @@ -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 diff --git a/lib/mongoid/fields/internal/array.rb b/lib/mongoid/fields/internal/array.rb index 66b3fa0122..56125d5869 100644 --- a/lib/mongoid/fields/internal/array.rb +++ b/lib/mongoid/fields/internal/array.rb @@ -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? diff --git a/lib/mongoid/fields/internal/foreign_keys/array.rb b/lib/mongoid/fields/internal/foreign_keys/array.rb index eedab449f5..19439a8665 100644 --- a/lib/mongoid/fields/internal/foreign_keys/array.rb +++ b/lib/mongoid/fields/internal/foreign_keys/array.rb @@ -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? diff --git a/spec/app/models/video.rb b/spec/app/models/video.rb index fb1749acc0..8056defce8 100644 --- a/spec/app/models/video.rb +++ b/spec/app/models/video.rb @@ -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 diff --git a/spec/functional/mongoid/relations/embedded/many_spec.rb b/spec/functional/mongoid/relations/embedded/many_spec.rb index 641bcc65f8..28ebb7e0d0 100644 --- a/spec/functional/mongoid/relations/embedded/many_spec.rb +++ b/spec/functional/mongoid/relations/embedded/many_spec.rb @@ -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 diff --git a/spec/unit/mongoid/fields/internal/array_spec.rb b/spec/unit/mongoid/fields/internal/array_spec.rb index ce7ffbdde5..8b4373119a 100644 --- a/spec/unit/mongoid/fields/internal/array_spec.rb +++ b/spec/unit/mongoid/fields/internal/array_spec.rb @@ -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 @@ -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 diff --git a/spec/unit/mongoid/fields/internal/foreign_keys/array_spec.rb b/spec/unit/mongoid/fields/internal/foreign_keys/array_spec.rb index 1f66b26cc2..80bf925593 100644 --- a/spec/unit/mongoid/fields/internal/foreign_keys/array_spec.rb +++ b/spec/unit/mongoid/fields/internal/foreign_keys/array_spec.rb @@ -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