Skip to content

Commit

Permalink
Add ability to pop embedded documents of a relation with persistence. C…
Browse files Browse the repository at this point in the history
…loses #1212.
  • Loading branch information
durran committed Feb 11, 2012
1 parent 831cb55 commit 17f3b00
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -134,6 +134,11 @@ For instructions on upgrading to newer versions, visit

* \#1348 Eager loading is now supported on many-to-many relations.

* \#1212 Embedded documents can now be popped off a relation with persistence.

band.albums.pop # Pop 1 document and persist the removal.
band.albums.pop(3) # Pop 3 documents and persist the removal.

* \#1081 Mongoid indexes both id and type as a compound index when providing
`index: true` to a polymorphic belongs_to.

Expand Down
25 changes: 25 additions & 0 deletions lib/mongoid/relations/embedded/many.rb
Expand Up @@ -261,6 +261,31 @@ def in_memory
target
end

# Pop documents off the relation. This can be a single document or
# multiples, and will automatically persist the changes.
#
# @example Pop a single document.
# relation.pop
#
# @example Pop multiple documents.
# relation.pop(3)
#
# @param [ Integer ] count The number of documents to pop, or 1 if not
# provided.
#
# @return [ Document, Array<Document> ] The popped document(s).
#
# @since 3.0.0
def pop(count = nil)
if count
docs = target[target.size - count, target.size]
return nil unless docs
docs.each { |doc| delete(doc) }
else
delete(target[-1])
end
end

# Substitutes the supplied target documents for the existing documents
# in the relation.
#
Expand Down
100 changes: 100 additions & 0 deletions spec/mongoid/relations/embedded/many_spec.rb
Expand Up @@ -2149,6 +2149,106 @@ class TrackingIdValidationHistory
end
end

describe "#pop" do

let(:person) do
Person.create
end

context "when no argument is provided" do

let!(:address_one) do
person.addresses.create(:street => "sonnenallee")
end

let!(:address_two) do
person.addresses.create(:street => "hermannstr")
end

let!(:popped) do
person.addresses.pop
end

it "returns the popped document" do
popped.should eq(address_two)
end

it "removes the document from the relation" do
person.addresses.should eq([ address_one ])
end

it "persists the pop" do
person.reload.addresses.should eq([ address_one ])
end
end

context "when an integer is provided" do

let!(:address_one) do
person.addresses.create(:street => "sonnenallee")
end

let!(:address_two) do
person.addresses.create(:street => "hermannstr")
end

context "when the number is not larger than the relation" do

let!(:popped) do
person.addresses.pop(2)
end

it "returns the popped documents" do
popped.should eq([ address_one, address_two ])
end

it "removes the document from the relation" do
person.addresses.should be_empty
end

it "persists the pop" do
person.reload.addresses.should be_empty
end
end

context "when the number is larger than the relation" do

let!(:popped) do
person.addresses.pop(4)
end

it "returns the popped documents" do
popped.should eq([ address_one, address_two ])
end

it "removes the document from the relation" do
person.addresses.should be_empty
end

it "persists the pop" do
person.reload.addresses.should be_empty
end
end
end

context "when the relation is empty" do

context "when providing no number" do

it "returns nil" do
person.addresses.pop.should be_nil
end
end

context "when providing a number" do

it "returns nil" do
person.addresses.pop(2).should be_nil
end
end
end
end

describe "#scoped" do

let(:person) do
Expand Down

0 comments on commit 17f3b00

Please sign in to comment.