Permalink
Browse files

Allowing Document#destroy on an embedded document

  • Loading branch information...
1 parent 6ce2037 commit 8d9d33021423d9131d0f865158090dec1ee4a558 @durran durran committed Dec 29, 2009
@@ -10,7 +10,8 @@ class Destroy
# doc: A new +Document+ that is going to be destroyed.
def self.execute(doc)
doc.run_callbacks :before_destroy
- doc.collection.remove(:_id => doc.id)
+ parent = doc.parent
+ parent ? parent.remove(doc) : doc.collection.remove(:_id => doc.id)
doc.run_callbacks :after_destroy
end
end
View
@@ -253,6 +253,15 @@ def reload
@attributes = collection.find_one(:_id => id).with_indifferent_access
end
+ # Remove a child document from this parent +Document+. Will reset the
+ # memoized association and notify the parent of the change.
+ def remove(child)
+ name = child.association_name
+ @attributes.remove(name, child.attributes)
+ remove_instance_variable("@#{name}")
+ notify
+ end
+
# Return the root +Document+ in the object graph. If the current +Document+
# is the root object in the graph it will return self.
def root
@@ -3,6 +3,21 @@ module Mongoid #:nodoc:
module Extensions #:nodoc:
module Hash #:nodoc:
module Accessors #:nodoc:
+
+ # Remove a set of attributes from a hash. If the attributes are
+ # contained in an array it will remove it from the array, otherwise it
+ # will delete the child attribute completely.
+ def remove(key, attrs)
+ elements = self[key]
+ if elements
+ key.singular? ? self[key] = nil : elements.delete(attrs)
+ end
+ end
+
+ # Inserts new attributes into the hash. If the elements are present in
+ # the hash it will update them, otherwise it will add the new
+ # attributes into the hash as either a child hash or child array of
+ # hashes.
def insert(key, attrs)
elements = self[key]
if elements
@@ -8,7 +8,8 @@
@collection = stub_everything
@document = stub(:run_callbacks => true,
:collection => @collection,
- :id => "1")
+ :id => "1",
+ :parent => false)
end
it "runs the before and after destroy callbacks" do
@@ -22,6 +23,22 @@
Mongoid::Commands::Destroy.execute(@document)
end
+ context "when the document is embedded" do
+
+ before do
+ @parent = Person.new
+ @address = Address.new(:street => "Genoa Pl")
+ @parent.addresses << @address
+ end
+
+ it "removes the document from the parent attributes" do
+ @parent.addresses.should == [@address]
+ Mongoid::Commands::Destroy.execute(@address)
+ @parent.addresses.should be_empty
+ end
+
+ end
+
end
end
@@ -504,6 +504,40 @@
end
+ describe "#remove" do
+
+ context "when removing an element from a has many" do
+
+ before do
+ @person = Person.new
+ @address = Address.new(:street => "Testing")
+ @person.addresses << @address
+ end
+
+ it "removes the child document attributes" do
+ @person.remove(@address)
+ @person.addresses.size.should == 0
+ end
+
+ end
+
+ context "when removing a has one" do
+
+ before do
+ @person = Person.new
+ @name = Name.new(:first_name => "Neytiri")
+ @person.name = @name
+ end
+
+ it "removes the child document attributes" do
+ @person.remove(@name)
+ @person.name.document.should be_nil
+ end
+
+ end
+
+ end
+
describe "#root" do
before do
@@ -2,27 +2,73 @@
describe Mongoid::Extensions::Hash::Accessors do
- describe "#insert" do
+ before do
+ @hash = {
+ :_id => 1,
+ :title => "value",
+ :name => {
+ :_id => 2, :first_name => "Test", :last_name => "User"
+ },
+ :pet => {
+ :_id => 6,
+ :name => "Fido",
+ :vet_visits => [ { :date => Date.new(2007, 1, 1) } ]
+ },
+ :addresses => [
+ { :_id => 3, :street => "First Street" },
+ { :_id => 4, :street => "Second Street" }
+ ]
+ }
+ end
+
+ describe "#remove" do
+
+ context "when removing from an array" do
+
+ context "when the elements exist" do
+
+ it "removes the element from the array" do
+ @hash.remove(:addresses, { :_id => 3, :street => "First Street" })
+ @hash[:addresses].size.should == 1
+ end
+
+ end
+
+ context "when the elements do not exist" do
+
+ it "does not raise an error" do
+ @hash.remove(:aliases, { :_id => 3, :street => "First Street" })
+ end
+
+ end
- before do
- @hash = {
- :_id => 1,
- :title => "value",
- :name => {
- :_id => 2, :first_name => "Test", :last_name => "User"
- },
- :pet => {
- :_id => 6,
- :name => "Fido",
- :vet_visits => [ { :date => Date.new(2007, 1, 1) } ]
- },
- :addresses => [
- { :_id => 3, :street => "First Street" },
- { :_id => 4, :street => "Second Street" }
- ]
- }
end
+ context "when removing a single object" do
+
+ context "when the element exists" do
+
+ it "removes the element from the array" do
+ @hash.remove(:name, { :_id => 2, :first_name => "Test", :last_name => "User" })
+ @hash[:name].should be_nil
+ end
+
+ end
+
+ context "when the element does not exist" do
+
+ it "does not raise an error" do
+ @hash.remove(:alias, { :_id => 3, :street => "First Street" })
+ end
+
+ end
+
+ end
+
+ end
+
+ describe "#insert" do
+
context "when writing to a hash with a child array" do
context "when child attributes not present" do

0 comments on commit 8d9d330

Please sign in to comment.