diff --git a/CHANGELOG.md b/CHANGELOG.md index 5033e6192f..5c5a4db0f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ For instructions on upgrading to newer versions, visit ### Resolved Issues +* \#1640 Update consumers should be tied to the name of the collection + they persist to, not the name of the class. + * \#1636 Scopes no longer modify parent class scopes when subclassing. (Hans Hasselberg) diff --git a/lib/mongoid/collection.rb b/lib/mongoid/collection.rb index de33bbe9e4..ecbb8bf8fa 100644 --- a/lib/mongoid/collection.rb +++ b/lib/mongoid/collection.rb @@ -142,7 +142,7 @@ def master(options = {}) # # @since 2.0.0 def update(selector, document, options = {}) - updater = Threaded.update_consumer(klass) + updater = Threaded.update_consumer(name) if updater updater.consume(selector, document, options) else diff --git a/lib/mongoid/contexts/enumerable.rb b/lib/mongoid/contexts/enumerable.rb index 2ec03187d9..a6bae2f59b 100644 --- a/lib/mongoid/contexts/enumerable.rb +++ b/lib/mongoid/contexts/enumerable.rb @@ -210,6 +210,18 @@ def update_all(attributes = nil) protected + # Get the root class collection name. + # + # @example Get the root class collection name. + # context.collection_name + # + # @return [ String ] The name of the collection. + # + # @since 2.4.3 + def collection_name + root ? root.collection_name : nil + end + # Filters the documents against the criteria's selector # # @example Filter the documents. @@ -251,10 +263,22 @@ def limit(documents) documents end + # Get the root document for the enumerable. + # + # @example Get the root document. + # context.root + # + # @return [ Document ] The root. def root @root ||= documents.first.try(:_root) end + # Get the root class for the enumerable. + # + # @example Get the root class. + # context.root_class + # + # @return [ Class ] The root class. def root_class @root_class ||= root ? root.class : nil end diff --git a/lib/mongoid/relations/embedded/atomic.rb b/lib/mongoid/relations/embedded/atomic.rb index 2e96c301e7..53262c1757 100644 --- a/lib/mongoid/relations/embedded/atomic.rb +++ b/lib/mongoid/relations/embedded/atomic.rb @@ -55,13 +55,13 @@ module Atomic # # @since 2.0.0 def atomically(modifier, &block) - updater = Threaded.update_consumer(root_class) || - Threaded.set_update_consumer(root_class, MODIFIERS[modifier].new) + updater = Threaded.update_consumer(collection_name) || + Threaded.set_update_consumer(collection_name, MODIFIERS[modifier].new) count_executions do block.call if block end.tap do if @executions.zero? - Threaded.set_update_consumer(root_class, nil) + Threaded.set_update_consumer(collection_name, nil) updater.execute(collection) end end diff --git a/lib/mongoid/relations/proxy.rb b/lib/mongoid/relations/proxy.rb index d77ad5aff8..4aeab48d23 100644 --- a/lib/mongoid/relations/proxy.rb +++ b/lib/mongoid/relations/proxy.rb @@ -18,6 +18,7 @@ class Proxy # Backwards compatibility with Mongoid beta releases. delegate :klass, :to => :metadata delegate :bind_one, :unbind_one, :to => :binding + delegate :collection_name, :to => :base # Convenience for setting the target and the metadata properties since # all proxies will need to do this. diff --git a/spec/functional/mongoid/relations/embedded/many_spec.rb b/spec/functional/mongoid/relations/embedded/many_spec.rb index 0d88513919..a34ac070c0 100644 --- a/spec/functional/mongoid/relations/embedded/many_spec.rb +++ b/spec/functional/mongoid/relations/embedded/many_spec.rb @@ -317,6 +317,60 @@ end end + context "when setting for inherited docs" do + + context "when the parent collection is already accessed" do + + before do + Person.collection + end + + context "when setting via the subclass" do + + let(:doctor) do + Doctor.new + end + + let(:address_one) do + Address.new(:street => "tauentzien") + end + + before do + doctor.addresses = [ address_one ] + doctor.save + end + + it "sets the documents" do + doctor.addresses.should eq([ address_one ]) + end + + it "persists the document" do + doctor.reload.addresses.should eq([ address_one ]) + end + + context "when setting the relation multiple times" do + + let(:address_two) do + Address.new(:street => "kudamm") + end + + before do + doctor.addresses = [ address_two ] + doctor.save + end + + it "sets the new documents" do + doctor.addresses.should eq([ address_two ]) + end + + it "persits only the new documents" do + doctor.reload.addresses.should eq([ address_two ]) + end + end + end + end + end + context "when replacing an existing relation" do let(:person) do diff --git a/spec/unit/mongoid/relations/embedded/atomic_spec.rb b/spec/unit/mongoid/relations/embedded/atomic_spec.rb index 7918570db8..def27f2e6a 100644 --- a/spec/unit/mongoid/relations/embedded/atomic_spec.rb +++ b/spec/unit/mongoid/relations/embedded/atomic_spec.rb @@ -12,6 +12,10 @@ def collection def root_class Person end + + def collection_name + "people" + end end describe "#atomically" do @@ -35,7 +39,7 @@ def root_class it "puts the updater on the current thread" do klass.send(:atomically, :$set) do - Mongoid::Threaded.update_consumer(Person).should eq(set) + Mongoid::Threaded.update_consumer("people").should eq(set) end end end @@ -44,7 +48,7 @@ def root_class it "removes the updater from the current thread" do klass.send(:atomically, :$set) - Mongoid::Threaded.update_consumer(Person).should be_nil + Mongoid::Threaded.update_consumer("people").should be_nil end end end