diff --git a/CHANGELOG.md b/CHANGELOG.md index 50a02956ee..fc443db046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,9 @@ For instructions on upgrading to newer versions, visit * \#1557 Internal strategy class no longer conflicts with models. +* \#1551 Parent documents now return `true` for `Model#changed?` if only child + (embedded) documents have changed. + * \#1547 Resetting persisted children from a parent save when new waits until post callbacks, mirroring update functionality. diff --git a/lib/mongoid/dirty.rb b/lib/mongoid/dirty.rb index 66f1c899d8..95e671227a 100644 --- a/lib/mongoid/dirty.rb +++ b/lib/mongoid/dirty.rb @@ -24,7 +24,21 @@ def changed # # @since 2.4.0 def changed? - changed_attributes.any? + changed_attributes.any? || children_changed? + end + + # Have any children (embedded documents) of this document changed? + # + # @example Have any children changed? + # model.children_changed? + # + # @return [ true, false ] If any children have changed. + # + # @since 2.4.1 + def children_changed? + _children.any? do |child| + child.changed? + end end # Get the attribute changes. diff --git a/lib/mongoid/persistence/operations/update.rb b/lib/mongoid/persistence/operations/update.rb index 1753292779..8847d1dd32 100644 --- a/lib/mongoid/persistence/operations/update.rb +++ b/lib/mongoid/persistence/operations/update.rb @@ -42,15 +42,6 @@ class Update def persist prepare do unless updates.empty? - # @todo Durran: This is a temporary fix for #791 until we rewrite - # the dirty tracking to properly flag a document as changed if - # only embedded documents have changed. - if document.respond_to?(:updated_at) - if document.timestamping? && !document.updated_at_changed? - document.updated_at = Time.now - end - end - collection.update(selector, updates, options) conflicts.each_pair do |key, value| collection.update(selector, { key => value }, options) diff --git a/spec/functional/mongoid/dirty_spec.rb b/spec/functional/mongoid/dirty_spec.rb index 86abc76c67..9bdee3beee 100644 --- a/spec/functional/mongoid/dirty_spec.rb +++ b/spec/functional/mongoid/dirty_spec.rb @@ -6,6 +6,93 @@ [ Person, Preference ].each(&:delete_all) end + context "when only embedded documents change" do + + let!(:person) do + Person.create(:ssn => "132-11-1111") + end + + context "when the child is an embeds one" do + + context "when the child is new" do + + let!(:name) do + person.build_name(:first_name => "Gordon", :last_name => "Ramsay") + end + + it "flags the parent as changed" do + person.should be_changed + end + end + + context "when the child is modified" do + + let!(:name) do + person.create_name(:first_name => "Gordon", :last_name => "Ramsay") + end + + before do + name.first_name = "G" + end + + it "flags the parent as changed" do + person.should be_changed + end + end + + context "when the child is not modified" do + + let!(:name) do + person.create_name(:first_name => "Gordon", :last_name => "Ramsay") + end + + it "does not flag the parent as changed" do + person.should_not be_changed + end + end + end + + context "when the child is an embeds many" do + + context "when a child is new" do + + let!(:address) do + person.addresses.build(:street => "jakobstr.") + end + + it "flags the parent as changed" do + person.should be_changed + end + end + + context "when a child is modified" do + + let!(:address) do + person.addresses.create(:street => "jakobstr.") + end + + before do + address.city = "Berlin" + end + + it "flags the parent as changed" do + person.should be_changed + end + end + + context "when no child is modified" do + + let!(:address) do + person.addresses.create(:street => "skalitzerstr.") + end + + it "does not flag the parent as changed" do + person.should_not be_changed + end + end + end + end + context "when changing a hash of hashes" do let!(:person) do