require "spec_helper" describe Mongoid::Relations::Embedded::Many do [ :<<, :push ].each do |method| describe "##{method}" do context "when the parent is a new record" do let(:person) do Person.new end let(:address) do Address.new end let!(:added) do person.addresses.send(method, address) end it "appends to the target" do expect(person.addresses).to eq([ address ]) end it "sets the base on the inverse relation" do expect(address.addressable).to eq(person) end it "sets the same instance on the inverse relation" do expect(address.addressable).to eql(person) end it "does not save the new document" do expect(address).to_not be_persisted end it "sets the parent on the child" do expect(address._parent).to eq(person) end it "sets the metadata on the child" do expect(address.__metadata).to_not be_nil end it "sets the index on the child" do expect(address._index).to eq(0) end it "returns the relation" do expect(added).to eq(person.addresses) end context "with a limiting default scope" do context "when the document matches the scope" do let(:active) do Appointment.new end before do person.appointments.send(method, active) end it "appends to the target" do expect(person.appointments.target).to eq([ active ]) end it "appends to the _unscoped" do expect(person.appointments.send(:_unscoped)).to eq([ active ]) end end context "when the document does not match the scope" do let(:inactive) do Appointment.new(active: false) end before do person.appointments.send(method, inactive) end it "doesn't append to the target" do expect(person.appointments.target).to_not eq([ inactive ]) end it "appends to the _unscoped" do expect(person.appointments.send(:_unscoped)).to eq([ inactive ]) end end end end context "when the parent is not a new record" do let(:person) do Person.create end let(:address) do Address.new end before do person.addresses.send(method, address) end it "saves the new document" do expect(address).to be_persisted end end context "when appending more than one document at once" do let(:person) do Person.create end let(:address_one) do Address.new end let(:address_two) do Address.new end let!(:added) do person.addresses.send(method, [ address_one, address_two ]) end it "saves the first document" do expect(address_one).to be_persisted end it "saves the second document" do expect(address_two).to be_persisted end it "returns the relation" do expect(added).to eq(person.addresses) end end context "when the parent and child have a cyclic relation" do context "when the parent is a new record" do let(:parent_role) do Role.new end let(:child_role) do Role.new end before do parent_role.child_roles.send(method, child_role) end it "appends to the target" do expect(parent_role.child_roles).to eq([ child_role ]) end it "sets the base on the inverse relation" do expect(child_role.parent_role).to eq(parent_role) end it "sets the same instance on the inverse relation" do expect(child_role.parent_role).to eql(parent_role) end it "does not save the new document" do expect(child_role).to_not be_persisted end it "sets the parent on the child" do expect(child_role._parent).to eq(parent_role) end it "sets the metadata on the child" do expect(child_role.__metadata).to_not be_nil end it "sets the index on the child" do expect(child_role._index).to eq(0) end end context "when the parent is not a new record" do let(:parent_role) do Role.create(name: "CEO") end let(:child_role) do Role.new(name: "COO") end before do parent_role.child_roles.send(method, child_role) end it "saves the new document" do expect(child_role).to be_persisted end end end context "when the child has one sided many to many relation" do let(:person) do Person.create end let(:message) do Message.new end context "assign parent first" do before do message.person = person message.receviers.send(method, person) end it "appends to the relation array" do expect(message.receviers).to include(person) end end context "not assign parent" do before do message.receviers.send(method, person) end it "appends to the relation array" do expect(message.receviers).to include(person) end end end end end describe "#=" do context "when the parent is a new record" do let(:person) do Person.new end let(:address) do Address.new end before do person.addresses = [ address ] end it "sets the target of the relation" do expect(person.addresses).to eq([ address ]) end it "sets the _unscoped of the relation" do expect(person.addresses.send(:_unscoped)).to eq([ address ]) end it "sets the base on the inverse relation" do expect(address.addressable).to eq(person) end it "sets the same instance on the inverse relation" do expect(address.addressable).to eql(person) end it "does not save the target" do expect(address).to_not be_persisted end it "sets the parent on the child" do expect(address._parent).to eq(person) end it "sets the metadata on the child" do expect(address.__metadata).to_not be_nil end it "sets the index on the child" do expect(address._index).to eq(0) end end context "when the parent is not a new record" do let(:person) do Person.create end let(:address) do Address.new end context "when setting directly" do before do person.addresses = [ address ] end it "saves the target" do expect(address).to be_persisted end end context "when setting via an overridden method from the parent" do let!(:person) do Person.create end let!(:address) do person.addresses.create(street: "Alt Treptow") end let!(:new_address) do Address.new(street: "Tempelhofer Damm") end before do person.update_attributes(set_addresses: [ new_address ]) end it "overwrites the existing addresses" do expect(person.reload.addresses).to eq([ new_address ]) end end context "when setting via the parent attributes" do before do person.attributes = { addresses: [ address ] } end it "sets the relation" do expect(person.addresses).to eq([ address ]) end it "does not save the target" do expect(address).to_not be_persisted end context "when setting the relation multiple times" do let(:address_two) do Address.new(street: "kudamm") end before do person.addresses = [ address_two ] person.save end it "sets the new documents" do expect(person.addresses).to eq([ address_two ]) end it "persits only the new documents" do expect(person.reload.addresses).to eq([ address_two ]) end end 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 expect(doctor.addresses).to eq([ address_one ]) end it "persists the document" do expect(doctor.reload.addresses).to 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 expect(doctor.addresses).to eq([ address_two ]) end it "persits only the new documents" do expect(doctor.reload.addresses).to eq([ address_two ]) end end end end end context "when replacing an existing relation" do let(:person) do Person.create(addresses: [ Address.new(street: "1st St"), Address.new(street: "2nd St") ]) end let(:address) do Address.new(street: "3rd St") end before do person.addresses = [ address ] end it "deletes the old documents" do expect(person.reload.addresses).to eq([ address ]) end end context "when the relation has an unusual name" do module MyCompany module Model class TrackingId include Mongoid::Document include Mongoid::Timestamps store_in collection: "tracking_ids" embeds_many \ :validation_history, class_name: "MyCompany::Model::TrackingIdValidationHistory" end class TrackingIdValidationHistory include Mongoid::Document field :old_state, type: String field :new_state, type: String field :when_changed, type: DateTime embedded_in :tracking_id, class_name: "MyCompany::Model::TrackingId" end end end let(:tracking_id) do MyCompany::Model::TrackingId.create end let(:history) do MyCompany::Model::TrackingIdValidationHistory.new(old_state: "Test") end before do tracking_id.validation_history << history end it "allows creation of the embedded document" do expect(tracking_id.validation_history.size).to eq(1) end it "saves the relation" do expect(history).to be_persisted end it "remains on reload" do expect(tracking_id.reload.validation_history.size).to eq(1) end end context "when the relation has address in the name" do let(:slave) do Slave.new(first_name: "Test") end before do ActiveSupport::Inflector.inflections do |inflect| inflect.singular("address_numbers", "address_number") end slave.address_numbers << AddressNumber.new(country_code: 1) slave.save end it "requires an inflection to determine the class" do expect(slave.reload.address_numbers.size).to eq(1) end end context "when setting the entire tree via a hash" do let(:person) do Person.create end let!(:address_one) do person.addresses.create(street: "Tauentzienstr") end let!(:address_two) do person.addresses.create(street: "Kudamm") end let(:attributes) do person.as_document.dup end context "when the attributes have changed" do before do attributes["addresses"][0]["city"] = "Berlin" person.update_attributes(attributes) end it "sets the new attributes" do expect(person.addresses.first.city).to eq("Berlin") end it "persists the changes" do expect(person.reload.addresses.first.city).to eq("Berlin") end end end context "when setting an embedded sub-document tree via a hash" do let(:person) do Person.create end let!(:address_one) do person.addresses.create(street: "Tauentzienstr") end let!(:location_one) do person.addresses.first.locations.create(name: "Work") end let(:attributes) do person.addresses.first.as_document.dup end context "when the attributes have changed" do before do attributes["city"] = "Berlin" attributes["locations"][0]["name"] = "Home" person.addresses.first.update_attributes(attributes) end it "sets the new attributes on the address" do expect(person.addresses.first.city).to eq("Berlin") end it "sets the new attributes on the location" do expect(person.addresses.first.locations.first.name).to eq("Home") end it "persists the changes to the address" do expect(person.reload.addresses.first.city).to eq("Berlin") end it "persists the changes to the location" do expect(person.reload.addresses.first.locations.first.name).to eq("Home") end it "does not persist the locations collection to the person document" do expect(person.reload[:locations]).to be_nil end end end context "when the parent and child have a cyclic relation" do context "when the parent is a new record" do let(:parent_role) do Role.new end let(:child_role) do Role.new end before do parent_role.child_roles = [ child_role ] end it "sets the target of the relation" do expect(parent_role.child_roles).to eq([ child_role ]) end it "sets the base on the inverse relation" do expect(child_role.parent_role).to eq(parent_role) end it "sets the same instance on the inverse relation" do expect(child_role.parent_role).to eql(parent_role) end it "does not save the target" do expect(child_role).to_not be_persisted end it "sets the parent on the child" do expect(child_role._parent).to eq(parent_role) end it "sets the metadata on the child" do expect(child_role.__metadata).to_not be_nil end it "sets the index on the child" do expect(child_role._index).to eq(0) end end context "when the parent is not a new record" do let(:parent_role) do Role.create(name: "CTO") end let(:child_role) do Role.new end before do parent_role.child_roles = [ child_role ] end it "saves the target" do expect(child_role).to be_persisted end end end end describe "#= nil" do context "when the relationship is polymorphic" do context "when the parent is a new record" do let(:person) do Person.new end let(:address) do Address.new end before do person.addresses = [ address ] person.addresses = nil end it "sets the relation to empty" do expect(person.addresses).to be_empty end it "sets the unscoped to empty" do expect(person.addresses.send(:_unscoped)).to be_empty end it "removes the inverse relation" do expect(address.addressable).to be_nil end end context "when the inverse is already nil" do let(:person) do Person.new end before do person.addresses = nil end it "sets the relation to empty" do expect(person.addresses).to be_empty end end context "when the parent is persisted" do let(:person) do Person.create end let(:address) do Address.new end context "when setting directly" do before do person.addresses = [ address ] person.addresses = nil end it "sets the relation to empty" do expect(person.addresses).to be_empty end it "sets the relation to empty in the database" do expect(person.reload.addresses).to be_empty end it "removed the inverse relation" do expect(address.addressable).to be_nil end it "deletes the child document" do expect(address).to be_destroyed end end context "when setting via attributes" do before do person.addresses = [ address ] person.attributes = { addresses: nil } end it "sets the relation to empty" do expect(person.addresses).to be_empty end it "deletes the child document" do expect(address).to be_destroyed end context "when saving the parent" do before do person.save person.reload end it "persists the deletion" do expect(person.addresses).to be_empty end end end end context "when setting on a reload" do let(:person) do Person.create end let(:address) do Address.new end let(:reloaded) do person.reload end before do person.reload.addresses = [ address ] person.reload.addresses = nil end it "sets the relation to empty" do expect(person.addresses).to be_empty end it "sets the relation to empty in the database" do expect(reloaded.addresses).to be_empty end end end context "when the relationship is cyclic" do context "when the parent is a new record" do let(:parent_role) do Role.new end let(:child_role) do Role.new end before do parent_role.child_roles = [ child_role ] parent_role.child_roles = nil end it "sets the relation to empty" do expect(parent_role.child_roles).to be_empty end it "removes the inverse relation" do expect(child_role.parent_role).to be_nil end end context "when the inverse is already nil" do let(:parent_role) do Role.new end before do parent_role.child_roles = nil end it "sets the relation to empty" do expect(parent_role.child_roles).to be_empty end end context "when the documents are not new records" do let(:parent_role) do Role.create end let(:child_role) do Role.new end before do parent_role.child_roles = [ child_role ] parent_role.child_roles = nil end it "sets the relation to empty" do expect(parent_role.child_roles).to be_empty end it "removed the inverse relation" do expect(child_role.parent_role).to be_nil end it "deletes the child document" do expect(child_role).to be_destroyed end end end end describe "#as_document" do let!(:person) do Person.create end context "when the relation has no default scope" do let!(:address) do person.addresses.create(street: "one") end let(:document) do person.reload.addresses.as_document end it "returns the documents as an array of hashes" do expect(document).to eq([ address.as_document ]) end end context "when the relation has a default scope" do context "when the default scope sorts" do let(:cough) do Symptom.new(name: "cough") end let(:headache) do Symptom.new(name: "headache") end before do person.symptoms.concat([ headache, cough ]) end let(:document) do person.reload.symptoms.as_document end it "returns the unscoped documents as an array of hashes" do expect(document).to eq([ headache.as_document, cough.as_document ]) end end context "when the default scope limits" do let(:active) do Appointment.new end let(:inactive) do Appointment.new(active: false) end before do person.appointments.concat([ active, inactive ]) end let(:document) do person.reload.appointments.as_document end it "returns the unscoped documents as an array of hashes" do expect(document).to eq([ active.as_document, inactive.as_document ]) end end end end [ :build, :new ].each do |method| describe "#build" do context "when the relation is not cyclic" do let(:person) do Person.new end let(:address) do person.addresses.send(method, street: "Bond") do |address| address.state = "CA" end end it "appends to the target" do expect(person.addresses).to eq([ address ]) end it "appends to the unscoped" do expect(person.addresses.send(:_unscoped)).to eq([ address ]) end it "sets the base on the inverse relation" do expect(address.addressable).to eq(person) end it "does not save the new document" do expect(address).to_not be_persisted end it "sets the parent on the child" do expect(address._parent).to eq(person) end it "sets the metadata on the child" do expect(address.__metadata).to_not be_nil end it "sets the index on the child" do expect(address._index).to eq(0) end it "writes to the attributes" do expect(address.street).to eq("Bond") end it "calls the passed block" do expect(address.state).to eq("CA") end end context "when the relation is cyclic" do let(:parent_role) do Role.new end let(:child_role) do parent_role.child_roles.send(method, name: "CTO") end it "appends to the target" do expect(parent_role.child_roles).to eq([ child_role ]) end it "sets the base on the inverse relation" do expect(child_role.parent_role).to eq(parent_role) end it "does not save the new document" do expect(child_role).to_not be_persisted end it "sets the parent on the child" do expect(child_role._parent).to eq(parent_role) end it "sets the metadata on the child" do expect(child_role.__metadata).to_not be_nil end it "sets the index on the child" do expect(child_role._index).to eq(0) end it "writes to the attributes" do expect(child_role.name).to eq("CTO") end end context "when providing nested attributes" do let(:person) do Person.create end let(:address) do person.addresses.send( method, street: "Bond", locations_attributes: { "1" => { "name" => "Home" } } ) end context "when followed by a save" do before do address.save end let(:location) do person.reload.addresses.first.locations.first end it "persists the deeply embedded document" do expect(location.name).to eq("Home") end end end end end describe ".builder" do let(:base) do Person.new end let(:target) do [ address ] end let(:metadata) do Person.relations["addresses"] end let(:relation) do described_class.new(base, target, metadata) end let(:document) do Address.new end it "returns the many builder" do expect( described_class.builder(base, metadata, document) ).to be_a(Mongoid::Relations::Builders::Embedded::Many) end end describe "#clear" do context "when the parent has been persisted" do let(:person) do Person.create end context "when the children are persisted" do let!(:address) do person.addresses.create(street: "High St") end let!(:relation) do person.addresses.clear end it "clears out the relation" do expect(person.addresses).to be_empty end it "clears the unscoped" do expect(person.addresses.send(:_unscoped)).to be_empty end it "marks the documents as deleted" do expect(address).to be_destroyed end it "deletes the documents from the db" do expect(person.reload.addresses).to be_empty end it "returns the relation" do expect(relation).to be_empty end end context "when the children are not persisted" do let!(:address) do person.addresses.build(street: "High St") end let!(:relation) do person.addresses.clear end it "clears out the relation" do expect(person.addresses).to be_empty end end end context "when the parent is not persisted" do let(:person) do Person.new end let!(:address) do person.addresses.build(street: "High St") end let!(:relation) do person.addresses.clear end it "clears out the relation" do expect(person.addresses).to be_empty end end end describe "#concat" do context "when the parent is a new record" do let(:person) do Person.new end let(:address) do Address.new end before do person.addresses.concat([ address ]) end it "appends to the target" do expect(person.addresses).to eq([ address ]) end it "appends to the unscoped" do expect(person.addresses.send(:_unscoped)).to eq([ address ]) end it "sets the base on the inverse relation" do expect(address.addressable).to eq(person) end it "sets the same instance on the inverse relation" do expect(address.addressable).to eql(person) end it "does not save the new document" do expect(address).to_not be_persisted end it "sets the parent on the child" do expect(address._parent).to eq(person) end it "sets the metadata on the child" do expect(address.__metadata).to_not be_nil end it "sets the index on the child" do expect(address._index).to eq(0) end end context "when the parent is not a new record" do let(:person) do Person.create end let(:address) do Address.new end before do person.addresses.concat([ address ]) end it "saves the new document" do expect(address).to be_persisted end end context "when concatenating an empty array" do let(:person) do Person.create end before do expect(person.addresses).to_not receive(:batch_insert) person.addresses.concat([]) end it "doesn't update the target" do expect(person.addresses).to be_empty end end context "when appending more than one document at once" do let(:person) do Person.create end let(:address_one) do Address.new end let(:address_two) do Address.new end before do person.addresses.concat([ address_one, address_two ]) end it "saves the first document" do expect(address_one).to be_persisted end it "saves the second document" do expect(address_two).to be_persisted end end context "when the parent and child have a cyclic relation" do context "when the parent is a new record" do let(:parent_role) do Role.new end let(:child_role) do Role.new end before do parent_role.child_roles.concat([ child_role ]) end it "appends to the target" do expect(parent_role.child_roles).to eq([ child_role ]) end it "sets the base on the inverse relation" do expect(child_role.parent_role).to eq(parent_role) end it "sets the same instance on the inverse relation" do expect(child_role.parent_role).to eql(parent_role) end it "does not save the new document" do expect(child_role).to_not be_persisted end it "sets the parent on the child" do expect(child_role._parent).to eq(parent_role) end it "sets the metadata on the child" do expect(child_role.__metadata).to_not be_nil end it "sets the index on the child" do expect(child_role._index).to eq(0) end end context "when the parent is not a new record" do let(:parent_role) do Role.create(name: "CEO") end let(:child_role) do Role.new(name: "COO") end before do parent_role.child_roles.concat([ child_role ]) end it "saves the new document" do expect(child_role).to be_persisted end end end end describe "#count" do let(:person) do Person.create end before do person.addresses.create(street: "Upper") person.addresses.build(street: "Bond") end it "returns the number of persisted documents" do expect(person.addresses.count).to eq(1) end end describe "#create" do context "when providing multiple attributes" do let(:person) do Person.create end let!(:addresses) do person.addresses.create([{ street: "Bond" }, { street: "Upper" }]) end it "creates multiple documents" do expect(addresses.size).to eq(2) end it "sets the first attributes" do expect(addresses.first.street).to eq("Bond") end it "sets the second attributes" do expect(addresses.last.street).to eq("Upper") end it "persists the children" do expect(person.addresses.count).to eq(2) end end context "when the relation is not cyclic" do let(:person) do Person.create end let!(:address) do person.addresses.create(street: "Bond") do |address| address.state = "CA" end end it "appends to the target" do expect(person.reload.addresses).to eq([ address ]) end it "appends to the unscoped" do expect(person.reload.addresses.send(:_unscoped)).to eq([ address ]) end it "sets the base on the inverse relation" do expect(address.addressable).to eq(person) end it "saves the document" do expect(address).to be_persisted end it "sets the parent on the child" do expect(address._parent).to eq(person) end it "sets the metadata on the child" do expect(address.__metadata).to_not be_nil end it "sets the index on the child" do expect(address._index).to eq(0) end it "writes to the attributes" do expect(address.street).to eq("Bond") end it "calls the passed block" do expect(address.state).to eq("CA") end context "when embedding a multi word named document" do let!(:component) do person.address_components.create(street: "Test") end it "saves the embedded document" do expect(person.reload.address_components.first).to eq(component) end end end context "when the relation is cyclic" do let!(:entry) do Entry.create(title: "hi") end let!(:child_entry) do entry.child_entries.create(title: "hello") end it "creates a new child" do expect(child_entry).to be_persisted end end end describe "#create!" do let(:person) do Person.create end context "when providing multiple attributes" do let!(:addresses) do person.addresses.create!([{ street: "Bond" }, { street: "Upper" }]) end it "creates multiple documents" do expect(addresses.size).to eq(2) end it "sets the first attributes" do expect(addresses.first.street).to eq("Bond") end it "sets the second attributes" do expect(addresses.last.street).to eq("Upper") end it "persists the children" do expect(person.addresses.count).to eq(2) end end context "when validation passes" do let(:address) do person.addresses.create!(street: "Bond") end it "appends to the target" do expect(person.addresses).to eq([ address ]) end it "appends to the unscoped" do expect(person.addresses.send(:_unscoped)).to eq([ address ]) end it "sets the base on the inverse relation" do expect(address.addressable).to eq(person) end it "saves the document" do expect(address).to be_persisted end it "sets the parent on the child" do expect(address._parent).to eq(person) end it "sets the metadata on the child" do expect(address.__metadata).to_not be_nil end it "sets the index on the child" do expect(address._index).to eq(0) end it "writes to the attributes" do expect(address.street).to eq("Bond") end end context "when validation fails" do it "raises an error" do expect { person.addresses.create!(street: "1") }.to raise_error(Mongoid::Errors::Validations) end end end describe "#delete" do let(:person) do Person.new end let(:address_one) do Address.new(street: "first") end let(:address_two) do Address.new(street: "second") end before do person.addresses << [ address_one, address_two ] end context "when the document exists in the relation" do let!(:deleted) do person.addresses.delete(address_one) end it "deletes the document" do expect(person.addresses).to eq([ address_two ]) end it "deletes the document from the unscoped" do expect(person.addresses.send(:_unscoped)).to eq([ address_two ]) end it "reindexes the relation" do expect(address_two._index).to eq(0) end it "returns the document" do expect(deleted).to eq(address_one) end end context "when the document does not exist" do it "returns nil" do expect(person.addresses.delete(Address.new)).to be_nil end end end describe "#delete_if" do let(:person) do Person.create end context "when the documents are new" do let!(:address_one) do person.addresses.build(street: "Bond") end let!(:address_two) do person.addresses.build(street: "Upper") end context "when a block is provided" do let!(:deleted) do person.addresses.delete_if do |doc| doc.street == "Bond" end end it "removes the matching documents" do expect(person.addresses.size).to eq(1) end it "removes from the unscoped" do expect(person.addresses.send(:_unscoped).size).to eq(1) end it "returns the relation" do expect(deleted).to eq(person.addresses) end end context "when no block is provided" do let!(:deleted) do person.addresses.delete_if end it "returns an enumerator" do expect(deleted).to be_a(Enumerator) end end end context "when the documents persisted" do let!(:address_one) do person.addresses.create(street: "Bond") end let!(:address_two) do person.addresses.create(street: "Upper") end context "when a block is provided" do let!(:deleted) do person.addresses.delete_if do |doc| doc.street == "Bond" end end it "deletes the matching documents" do expect(person.addresses.count).to eq(1) end it "deletes the matching documents from the db" do expect(person.reload.addresses.count).to eq(1) end it "returns the relation" do expect(deleted).to eq(person.addresses) end end end context "when the documents are empty" do context "when a block is provided" do let!(:deleted) do person.addresses.delete_if do |doc| doc.street == "Bond" end end it "deletes the matching documents" do expect(person.addresses.count).to eq(0) end it "deletes all the documents from the db" do expect(person.reload.addresses.count).to eq(0) end it "returns the relation" do expect(deleted).to eq(person.addresses) end end end end [ :delete_all, :destroy_all ].each do |method| describe "##{method}" do let(:person) do Person.create end context "when the documents are new" do let!(:address_one) do person.addresses.build(street: "Bond") end let!(:address_two) do person.addresses.build(street: "Upper") end context "when conditions are provided" do let!(:deleted) do person.addresses.send( method, { street: "Bond" } ) end it "removes the matching documents" do expect(person.addresses.size).to eq(1) end it "removes from the unscoped" do expect(person.addresses.send(:_unscoped).size).to eq(1) end it "returns the number deleted" do expect(deleted).to eq(1) end end context "when conditions are not provided" do let!(:deleted) do person.addresses.send(method) end it "removes all documents" do expect(person.addresses.size).to eq(0) end it "returns the number deleted" do expect(deleted).to eq(2) end end end context "when the documents persisted" do let!(:address_one) do person.addresses.create(street: "Bond") end let!(:address_two) do person.addresses.create(street: "Upper") end context "when conditions are provided" do let!(:deleted) do person.addresses.send( method, { street: "Bond" } ) end it "deletes the matching documents" do expect(person.addresses.count).to eq(1) end it "deletes the matching documents from the db" do expect(person.reload.addresses.count).to eq(1) end it "returns the number deleted" do expect(deleted).to eq(1) end end context "when conditions are not provided" do let!(:deleted) do person.addresses.send(method) end it "deletes all the documents" do expect(person.addresses.count).to eq(0) end it "deletes all the documents from the db" do expect(person.reload.addresses.count).to eq(0) end it "returns the number deleted" do expect(deleted).to eq(2) end end context "when removing and resaving" do let(:owner) do PetOwner.create(title: "AKC") end before do owner.pet = Pet.new(name: "Fido") owner.pet.vet_visits << VetVisit.new(date: Date.today) owner.save! owner.pet.vet_visits.destroy_all end it "removes the documents" do expect(owner.pet.vet_visits).to be_empty end it "allows addition and a resave" do owner.pet.vet_visits << VetVisit.new(date: Date.today) owner.save! expect(owner.pet.vet_visits.first).to be_persisted end end end context "when the documents empty" do context "when scoped" do let!(:deleted) do person.addresses.without_postcode.send(method) end it "deletes all the documents" do expect(person.addresses.count).to eq(0) end it "deletes all the documents from the db" do expect(person.reload.addresses.count).to eq(0) end it "returns the number deleted" do expect(deleted).to eq(0) end end context "when conditions are provided" do let!(:deleted) do person.addresses.send( method, conditions: { street: "Bond" } ) end it "deletes all the documents" do expect(person.addresses.count).to eq(0) end it "deletes all the documents from the db" do expect(person.reload.addresses.count).to eq(0) end it "returns the number deleted" do expect(deleted).to eq(0) end end context "when conditions are not provided" do let!(:deleted) do person.addresses.send(method) end it "deletes all the documents" do expect(person.addresses.count).to eq(0) end it "deletes all the documents from the db" do expect(person.reload.addresses.count).to eq(0) end it "returns the number deleted" do expect(deleted).to eq(0) end end end end end describe ".embedded?" do it "returns true" do expect(described_class).to be_embedded end end describe ".foreign_key_suffix" do it "returns nil" do expect(described_class.foreign_key_suffix).to be_nil end end describe "#exists?" do let!(:person) do Person.create end context "when documents exist in the database" do before do person.addresses.create(street: "Bond St") end it "returns true" do expect(person.addresses.exists?).to be true end end context "when no documents exist in the database" do before do person.addresses.build(street: "Hyde Park Dr") end it "returns false" do expect(person.addresses.exists?).to be false end end end describe "#find" do let(:person) do Person.new end let!(:address_one) do person.addresses.build(street: "Bond", city: "London") end let!(:address_two) do person.addresses.build(street: "Upper", city: "London") end context "when providing an id" do context "when the id matches" do let(:address) do person.addresses.find(address_one.id) end it "returns the matching document" do expect(address).to eq(address_one) end end context "when the id does not match" do context "when config set to raise error" do before do Mongoid.raise_not_found_error = true end it "raises an error" do expect { person.addresses.find(BSON::ObjectId.new) }.to raise_error(Mongoid::Errors::DocumentNotFound) end end context "when config set not to raise error" do let(:address) do person.addresses.find(BSON::ObjectId.new) end before do Mongoid.raise_not_found_error = false end after do Mongoid.raise_not_found_error = true end it "returns nil" do expect(address).to be_nil end end end end context "when providing an array of ids" do context "when the ids match" do let(:addresses) do person.addresses.find([ address_one.id, address_two.id ]) end it "returns the matching documents" do expect(addresses).to eq([ address_one, address_two ]) end end context "when the ids do not match" do context "when config set to raise error" do before do Mongoid.raise_not_found_error = true end it "raises an error" do expect { person.addresses.find([ BSON::ObjectId.new ]) }.to raise_error(Mongoid::Errors::DocumentNotFound) end end context "when config set not to raise error" do let(:addresses) do person.addresses.find([ BSON::ObjectId.new ]) end before do Mongoid.raise_not_found_error = false end after do Mongoid.raise_not_found_error = true end it "returns an empty array" do expect(addresses).to be_empty end end end end end describe "#find_or_create_by" do let(:person) do Person.create end let!(:address) do person.addresses.build(street: "Bourke", city: "Melbourne") end context "when the document exists" do let(:found) do person.addresses.find_or_create_by(street: "Bourke") end it "returns the document" do expect(found).to eq(address) end end context "when the document does not exist" do let(:found) do person.addresses.find_or_create_by(street: "King") do |address| address.state = "CA" end end it "sets the new document attributes" do expect(found.street).to eq("King") end it "returns a newly persisted document" do expect(found).to be_persisted end it "calls the passed block" do expect(found.state).to eq("CA") end end context "when the child belongs to another document" do let(:product) do Product.create end let(:purchase) do Purchase.create end let(:line_item) do purchase.line_items.find_or_create_by( product_id: product.id, product_type: product.class.name ) end it "properly creates the document" do expect(line_item.product).to eq(product) end end end describe "#find_or_create_by!" do let(:person) do Person.create end let!(:address) do person.addresses.build(street: "Bourke", city: "Melbourne") end context "when the document exists" do let(:found) do person.addresses.find_or_create_by!(street: "Bourke") end it "returns the document" do expect(found).to eq(address) end end context "when the document does not exist" do let(:found) do person.addresses.find_or_create_by!(street: "King") do |address| address.state = "CA" end end it "sets the new document attributes" do expect(found.street).to eq("King") end it "returns a newly persisted document" do expect(found).to be_persisted end it "calls the passed block" do expect(found.state).to eq("CA") end context "when validation fails" do it "raises an error" do expect { person.addresses.find_or_create_by!(street: "1") }.to raise_error(Mongoid::Errors::Validations) end end end context "when the child belongs to another document" do let(:product) do Product.create end let(:purchase) do Purchase.create end let(:line_item) do purchase.line_items.find_or_create_by( product_id: product.id, product_type: product.class.name ) end it "properly creates the document" do expect(line_item.product).to eq(product) end end end describe "#find_or_initialize_by" do let(:person) do Person.new end let!(:address) do person.addresses.build(street: "Bourke", city: "Melbourne") end context "when the document exists" do let(:found) do person.addresses.find_or_initialize_by(street: "Bourke") end it "returns the document" do expect(found).to eq(address) end end context "when the document does not exist" do let(:found) do person.addresses.find_or_initialize_by(street: "King") do |address| address.state = "CA" end end it "sets the new document attributes" do expect(found.street).to eq("King") end it "returns a non persisted document" do expect(found).to_not be_persisted end it "calls the passed block" do expect(found.state).to eq("CA") end end end describe ".macro" do it "returns embeds_many" do expect(described_class.macro).to eq(:embeds_many) end end describe "#max" do let(:person) do Person.new end let(:address_one) do Address.new(number: 5) end let(:address_two) do Address.new(number: 10) end before do person.addresses.push(address_one, address_two) end let(:max) do person.addresses.max do |a,b| a.number <=> b.number end end it "returns the document with the max value of the supplied field" do expect(max).to eq(address_two) end end describe "#max_by" do let(:person) do Person.new end let(:address_one) do Address.new(number: 5) end let(:address_two) do Address.new(number: 10) end before do person.addresses.push(address_one, address_two) end let(:max) do person.addresses.max_by(&:number) end it "returns the document with the max value of the supplied field" do expect(max).to eq(address_two) end end describe "#method_missing" do let!(:person) do Person.create end let!(:address_one) do person.addresses.create( street: "Market", state: "CA", services: [ "1", "2" ] ) end let!(:address_two) do person.addresses.create( street: "Madison", state: "NY", services: [ "1", "2" ] ) end context "when providing a single criteria" do context "when using a simple criteria" do let(:addresses) do person.addresses.where(state: "CA") end it "applies the criteria to the documents" do expect(addresses).to eq([ address_one ]) end end context "when using an $or criteria" do let(:addresses) do person.addresses.any_of({ state: "CA" }, { state: "NY" }) end it "applies the criteria to the documents" do expect(addresses).to eq([ address_one, address_two ]) end end context "when using array comparison" do let(:addresses) do person.addresses.where(services: [ "1", "2" ]) end it "applies the criteria to the documents" do expect(addresses).to eq([ address_one, address_two ]) end end end context "when providing a criteria class method" do let(:addresses) do person.addresses.california end it "applies the criteria to the documents" do expect(addresses).to eq([ address_one ]) end end context "when chaining criteria" do let(:addresses) do person.addresses.california.where(:street.in => [ "Market" ]) end it "applies the criteria to the documents" do expect(addresses).to eq([ address_one ]) end end context "when delegating methods" do describe "#distinct" do it "returns the distinct values for the fields" do expect(person.addresses.distinct(:street)).to eq([ "Market", "Madison"]) end end end end describe "#min" do let(:person) do Person.new end let(:address_one) do Address.new(number: 5) end let(:address_two) do Address.new(number: 10) end before do person.addresses.push(address_one, address_two) end let(:min) do person.addresses.min do |a,b| a.number <=> b.number end end it "returns the min value of the supplied field" do expect(min).to eq(address_one) end end describe "#min_by" do let(:person) do Person.new end let(:address_one) do Address.new(number: 5) end let(:address_two) do Address.new(number: 10) end before do person.addresses.push(address_one, address_two) end let(:min) do person.addresses.min_by(&:number) end it "returns the min value of the supplied field" do expect(min).to eq(address_one) end end describe ".nested_builder" do let(:metadata) do Person.relations["addresses"] end it "returns the many nested builder class" do expect( described_class.nested_builder(metadata, {}, {}) ).to be_a(Mongoid::Relations::Builders::NestedAttributes::Many) 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 expect(popped).to eq(address_two) end it "removes the document from the relation" do expect(person.addresses).to eq([ address_one ]) end it "persists the pop" do expect(person.reload.addresses).to 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 expect(popped).to eq([ address_one, address_two ]) end it "removes the document from the relation" do expect(person.addresses).to be_empty end it "persists the pop" do expect(person.reload.addresses).to 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 expect(popped).to eq([ address_one, address_two ]) end it "removes the document from the relation" do expect(person.addresses).to be_empty end it "persists the pop" do expect(person.reload.addresses).to be_empty end end end context "when the relation is empty" do context "when providing no number" do it "returns nil" do expect(person.addresses.pop).to be_nil end end context "when providing a number" do it "returns nil" do expect(person.addresses.pop(2)).to be_nil end end end end describe "#scoped" do let(:person) do Person.new end let(:scoped) do person.addresses.scoped end it "returns the relation criteria" do expect(scoped).to be_a(Mongoid::Criteria) end it "returns with an empty selector" do expect(scoped.selector).to be_empty end end describe "#respond_to?" do let(:person) do Person.new end let(:addresses) do person.addresses end Array.public_instance_methods.each do |method| context "when checking #{method}" do it "returns true" do expect(addresses.respond_to?(method)).to be true end end end Mongoid::Relations::Embedded::Many.public_instance_methods.each do |method| context "when checking #{method}" do it "returns true" do expect(addresses.respond_to?(method)).to be true end end end Address.scopes.keys.each do |method| context "when checking #{method}" do it "returns true" do expect(addresses.respond_to?(method)).to be true end end end it "supports 'include_private = boolean'" do expect { addresses.respond_to?(:Rational, true) }.not_to raise_error end end [ :size, :length ].each do |method| describe "##{method}" do let(:person) do Person.create end before do person.addresses.create(street: "Upper") person.addresses.build(street: "Bond") end it "returns the number of persisted documents" do expect(person.addresses.send(method)).to eq(2) end end end describe "#unscoped" do let(:person) do Person.new end let(:unscoped) do person.videos.unscoped end it "returns the relation criteria" do expect(unscoped).to be_a(Mongoid::Criteria) end it "returns with empty options" do expect(unscoped.options).to be_empty end it "returns with an empty selector" do expect(unscoped.selector).to be_empty end end describe "#update_all" do context "when there are no documents present" do let(:person) do Person.create end it "updates nothing" do expect(person.addresses.update_all(street: "test")).to be false end end context "when documents are present" do let(:person) do Person.create end let!(:address) do person.addresses.create(street: "Hobrecht", number: 27) end context "when updating with a where clause" do before do person.addresses. where(street: "Hobrecht"). update_all(number: 26, post_code: "12437") end it "resets the matching dirty flags" do expect(address).to_not be_changed end it "updates the first field" do expect(address.reload.number).to eq(26) end it "updates the second field" do expect(address.reload.post_code).to eq("12437") end it "does not wipe out other fields" do expect(address.reload.street).to eq("Hobrecht") end end end end describe ".valid_options" do it "returns the valid options" do expect(described_class.valid_options).to eq( [ :as, :cascade_callbacks, :cyclic, :order, :store_as, :before_add, :after_add, :before_remove, :after_remove ] ) end end describe ".validation_default" do it "returns true" do expect(described_class.validation_default).to be true end end context "when deeply embedding documents" do context "when updating the bottom level" do let!(:person) do Person.create end let!(:address) do person.addresses.create(street: "Joachimstr") end let!(:location) do address.locations.create(name: "work") end context "when updating with a hash" do before do address.update_attributes(locations: [{ name: "home" }]) end it "updates the attributes" do expect(address.locations.first.name).to eq("home") end it "overwrites the existing documents" do expect(address.locations.count).to eq(1) end it "persists the changes" do expect(address.reload.locations.count).to eq(1) end end end context "when building the tree through hashes" do let(:circus) do Circus.new(hash) end let(:animal) do circus.animals.first end let(:animal_name) do "Lion" end let(:tag_list) do "tigers, bears, oh my" end context "when the hash uses stringified keys" do let(:hash) do { 'animals' => [{ 'name' => animal_name, 'tag_list' => tag_list }] } end it "sets up the hierarchy" do expect(animal.circus).to eq(circus) end it "assigns the attributes" do expect(animal.name).to eq(animal_name) end it "uses custom writer methods" do expect(animal.tag_list).to eq(tag_list) end end context "when the hash uses symbolized keys" do let(:hash) do { animals: [{ name: animal_name, tag_list: tag_list }] } end it "sets up the hierarchy" do expect(animal.circus).to eq(circus) end it "assigns the attributes" do expect(animal.name).to eq(animal_name) end it "uses custom writer methods" do expect(animal.tag_list).to eq(tag_list) end end end context "when building the tree through pushes" do let(:quiz) do Quiz.new end let(:page) do Page.new end let(:page_question) do PageQuestion.new end before do quiz.pages << page page.page_questions << page_question end let(:question) do quiz.pages.first.page_questions.first end it "sets up the hierarchy" do expect(question).to eq(page_question) end end context "when building the tree through builds" do let!(:quiz) do Quiz.new end let!(:page) do quiz.pages.build end let!(:page_question) do page.page_questions.build end let(:question) do quiz.pages.first.page_questions.first end it "sets up the hierarchy" do expect(question).to eq(page_question) end end context "when creating a persisted tree" do let(:quiz) do Quiz.create end let(:page) do Page.new end let(:page_question) do PageQuestion.new end let(:question) do quiz.pages.first.page_questions.first end before do quiz.pages << page page.page_questions << page_question end it "sets up the hierarchy" do expect(question).to eq(page_question) end context "when reloading" do let(:from_db) do quiz.reload end let(:reloaded_question) do from_db.pages.first.page_questions.first end it "reloads the entire tree" do expect(reloaded_question).to eq(question) end end end end context "when deeply nesting documents" do context "when all documents are new" do let(:person) do Person.new end let(:address) do Address.new end let(:location) do Location.new end before do address.locations << location person.addresses << address end context "when saving the root" do before do person.save end it "persists the first level document" do expect(person.reload.addresses.first).to eq(address) end it "persists the second level document" do expect(person.reload.addresses[0].locations).to eq([ location ]) end end end end context "when attempting nil pushes and substitutes" do let(:home_phone) do Phone.new(number: "555-555-5555") end let(:office_phone) do Phone.new(number: "666-666-6666") end describe "replacing the entire embedded list" do context "when an embeds many relationship contains a nil as the first item" do let(:person) do Person.create! end let(:phone_list) do [nil, home_phone, office_phone] end before do person.phone_numbers = phone_list person.save! end it "ignores the nil and persist the remaining items" do reloaded = Person.find(person.id) expect(reloaded.phone_numbers).to eq([ home_phone, office_phone ]) end end context "when an embeds many relationship contains a nil in the middle of the list" do let(:person) do Person.create! end let(:phone_list) do [home_phone, nil, office_phone] end before do person.phone_numbers = phone_list person.save! end it "ignores the nil and persist the remaining items" do reloaded = Person.find(person.id) expect(reloaded.phone_numbers).to eq([ home_phone, office_phone ]) end end context "when an embeds many relationship contains a nil at the end of the list" do let(:person) do Person.create! end let(:phone_list) do [home_phone, office_phone, nil] end before do person.phone_numbers = phone_list person.save! end it "ignores the nil and persist the remaining items" do reloaded = Person.find(person.id) expect(reloaded.phone_numbers).to eq([ home_phone, office_phone ]) end end end describe "appending to the embedded list" do context "when appending a nil to the first position in an embedded list" do let(:person) do Person.create! phone_numbers: [] end before do person.phone_numbers << nil person.phone_numbers << home_phone person.phone_numbers << office_phone person.save! end it "ignores the nil and persist the remaining items" do reloaded = Person.find(person.id) expect(reloaded.phone_numbers).to eq(person.phone_numbers) end end context "when appending a nil into the middle of an embedded list" do let(:person) do Person.create! phone_numbers: [] end before do person.phone_numbers << home_phone person.phone_numbers << nil person.phone_numbers << office_phone person.save! end it "ignores the nil and persist the remaining items" do reloaded = Person.find(person.id) expect(reloaded.phone_numbers).to eq(person.phone_numbers) end end context "when appending a nil to the end of an embedded list" do let(:person) do Person.create! phone_numbers: [] end before do person.phone_numbers << home_phone person.phone_numbers << office_phone person.phone_numbers << nil person.save! end it "ignores the nil and persist the remaining items" do reloaded = Person.find(person.id) expect(reloaded.phone_numbers).to eq(person.phone_numbers) end end end end context "when accessing the parent in a destroy callback" do let!(:league) do League.create end let!(:division) do league.divisions.create end before do league.destroy end it "retains the reference to the parent" do expect(league.name).to eq("Destroyed") end end context "when updating the parent with all attributes" do let!(:person) do Person.create end let!(:address) do person.addresses.create end before do person.update_attributes(person.attributes) end it "does not duplicate the embedded documents" do expect(person.addresses).to eq([ address ]) end it "does not persist duplicate embedded documents" do expect(person.reload.addresses).to eq([ address ]) end end context "when embedding children named versions" do let(:acolyte) do Acolyte.create(name: "test") end context "when creating a child" do let(:version) do acolyte.versions.create(number: 1) end it "allows the operation" do expect(version.number).to eq(1) end context "when reloading the parent" do let(:from_db) do acolyte.reload end it "saves the child versions" do expect(from_db.versions).to eq([ version ]) end end end end context "when validating the parent before accessing the child" do let!(:account) do Account.new(name: "Testing").tap do |acct| acct.memberships.build acct.save end end let(:from_db) do Account.first end context "when saving" do before do account.name = "" account.save end it "does not lose the parent reference" do expect(from_db.memberships.first.account).to eq(account) end end context "when updating attributes" do before do from_db.update_attributes(name: "") end it "does not lose the parent reference" do expect(from_db.memberships.first.account).to eq(account) end end end context "when moving an embedded document from one parent to another" do let!(:person_one) do Person.create end let!(:person_two) do Person.create end let!(:address) do person_one.addresses.create(street: "Kudamm") end before do person_two.addresses << address end it "adds the document to the new paarent" do expect(person_two.addresses).to eq([ address ]) end it "sets the new parent on the document" do expect(address._parent).to eq(person_two) end context "when reloading the documents" do before do person_one.reload person_two.reload end it "persists the change to the new parent" do expect(person_two.addresses).to eq([ address ]) end it "keeps the address on the previous document" do expect(person_one.addresses).to eq([ address ]) end end end context "when the relation has a default scope" do let!(:person) do Person.create end context "when the default scope is a sort" do let(:cough) do Symptom.new(name: "cough") end let(:headache) do Symptom.new(name: "headache") end let(:nausea) do Symptom.new(name: "nausea") end before do person.symptoms.concat([ nausea, cough, headache ]) end context "when accessing the relation" do let(:symptoms) do person.reload.symptoms end it "applies the default scope" do expect(symptoms).to eq([ cough, headache, nausea ]) end end context "when modifying the relation" do let(:constipation) do Symptom.new(name: "constipation") end before do person.symptoms.push(constipation) end context "when reloading" do let(:symptoms) do person.reload.symptoms end it "applies the default scope" do expect(symptoms).to eq([ constipation, cough, headache, nausea ]) end end end context "when unscoping the relation" do let(:unscoped) do person.reload.symptoms.unscoped end it "removes the default scope" do expect(unscoped).to eq([ nausea, cough, headache ]) end end end end context "when indexing the documents" do let!(:person) do Person.create end context "when the documents have a limiting default scope" do let(:active) do Appointment.new end let(:inactive) do Appointment.new(active: false) end before do person.appointments.concat([ inactive, active ]) end let(:relation) do person.reload.appointments end it "retains the unscoped index for the excluded document" do expect(relation.send(:_unscoped).first._index).to eq(0) end it "retains the unscoped index for the included document" do expect(relation.first._index).to eq(1) end context "when a reindexing operation occurs" do before do relation.send(:reindex) end it "retains the unscoped index for the excluded document" do expect(relation.send(:_unscoped).first._index).to eq(0) end it "retains the unscoped index for the included document" do expect(relation.first._index).to eq(1) end end end end context "when the embedded document has an array field" do let!(:person) do Person.create 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 expect(video.genres).to eq([ "horror", "scifi" ]) end it "persists the value" do expect(video.reload.genres).to 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 expect(loaded_video.genres).to eq([ "comedy" ]) end it "persists the new value" do expect(loaded_video.reload.genres).to eq([ "comedy" ]) end end end end end context "when destroying an embedded document" do let(:person) do Person.create end let!(:address_one) do person.addresses.create(street: "hobrecht") end let!(:address_two) do person.addresses.create(street: "maybachufer") end before do address_one.destroy end it "destroys the document" do expect(address_one).to be_destroyed end it "reindexes the relation" do expect(address_two._index).to eq(0) end it "removes the document from the unscoped" do expect(person.addresses.send(:_unscoped)).to_not include(address_one) end context "when subsequently updating the next document" do before do address_two.update_attribute(:number, 10) end let(:addresses) do person.reload.addresses end it "updates the correct document" do expect(addresses.first.number).to eq(10) end it "does not add additional documents" do expect(addresses.count).to eq(1) end end end context "when adding a document" do let(:person) do Person.new end let(:address_one) do Address.new(street: "hobrecht") end let(:first_add) do person.addresses.push(address_one) end context "when chaining a second add" do let(:address_two) do Address.new(street: "friedel") end let(:result) do first_add.push(address_two) end it "adds both documents" do expect(result).to eq([ address_one, address_two ]) end end end context "when using dot notation in a criteria" do let(:person) do Person.new end let!(:address) do person.addresses.build(street: "hobrecht") end let!(:location) do address.locations.build(number: 5) end let(:criteria) do person.addresses.where("locations.number" => { "$gt" => 3 }) end it "allows the dot notation criteria" do expect(criteria).to eq([ address ]) end end context "when updating multiple levels in one update" do let!(:person) do Person.create( addresses: [ { locations: [{ name: "home" }]} ] ) end context "when updating with hashes" do let(:from_db) do Person.find(person.id) end before do from_db.update_attributes( addresses: [ { locations: [{ name: "work" }]} ] ) end let(:updated) do person.reload.addresses.first.locations.first end it "updates the nested document" do expect(updated.name).to eq("work") end end end context "when the embedded relation sorts on a boolean" do let(:circuit) do Circuit.create end let!(:bus_one) do circuit.buses.create(saturday: true) end let!(:bus_two) do circuit.buses.create(saturday: false) end it "orders properly with the boolean" do expect(circuit.reload.buses).to eq([ bus_two, bus_one ]) end end context "when batch replacing multiple relations in a single update" do let(:document) do Person.create end let(:person) do Person.find(document.id) end let!(:symptom_one) do person.symptoms.create end let!(:symptom_two) do person.symptoms.create end let!(:appointment_one) do person.appointments.create end let!(:appointment_two) do person.appointments.create end before do person.update_attributes( appointments: [ appointment_one.as_document, appointment_two.as_document ], symptoms: [ symptom_one.as_document, symptom_two.as_document ] ) end it "does not duplicate the first relation" do expect(person.reload.symptoms.count).to eq(2) end it "does not duplicate the second relation" do expect(person.reload.appointments.count).to eq(2) end end context "when pushing with a before_add callback" do let(:artist) do Artist.new end let(:song) do Song.new end context "when no errors are raised" do before do artist.songs << song end it "executes the callback" do expect(artist.before_add_called).to be true end it "executes the callback as proc" do expect(song.before_add_called).to be true end it "adds the document to the relation" do expect(artist.songs).to eq([song]) end end context "with errors" do before do expect(artist).to receive(:before_add_song).and_raise end it "does not add the document to the relation" do expect { artist.songs << song }.to raise_error expect(artist.songs).to be_empty end end end context "when pushing with an after_add callback" do let(:artist) do Artist.new end let(:label) do Label.new end it "executes the callback" do artist.labels << label expect(artist.after_add_called).to be true end context "when errors are raised" do before do expect(artist).to receive(:after_add_label).and_raise end it "adds the document to the relation" do expect { artist.labels << label }.to raise_error expect(artist.labels).to eq([ label ]) end end end context "#delete or #clear with before_remove callback" do let(:artist) do Artist.new end let(:song) do Song.new end before do artist.songs << song end context "when no errors are raised" do describe "#delete" do before do artist.songs.delete(song) end it "executes the callback" do expect(artist.before_remove_embedded_called).to be true end it "removes the document from the relation" do expect(artist.songs).to be_empty end end describe "#clear" do before do artist.songs.clear end it "executes the callback" do expect(artist.before_remove_embedded_called).to be true end it "shoud clear the relation" do expect(artist.songs).to be_empty end end context "when errors are raised" do before do expect(artist).to receive(:before_remove_song).and_raise end describe "#delete" do it "does not remove the document from the relation" do expect { artist.songs.delete(song) }.to raise_error expect(artist.songs).to eq([ song ]) end end describe "#clear" do it "removes the documents from the relation" do expect { artist.songs.clear }.to raise_error expect(artist.songs).to eq([ song ]) end end end end end context "#delete or #clear with after_remove callback" do let(:artist) do Artist.new end let(:label) do Label.new end before do artist.labels << label end context "when no errors are raised" do describe "#delete" do before do artist.labels.delete(label) end it "executes the callback" do expect(artist.after_remove_embedded_called).to be true end end describe "#clear" do before do artist.labels.clear end it "executes the callback" do artist.labels.clear expect(artist.after_remove_embedded_called).to be true end end end context "when errors are raised" do before do expect(artist).to receive(:after_remove_label).and_raise end describe "#delete" do before do expect { artist.labels.delete(label) }.to raise_error end it "removes the document from the relation" do expect(artist.labels).to be_empty end end describe "#clear" do before do expect { artist.labels.clear }.to raise_error end it "should remove from collection" do expect(artist.labels).to be_empty end end end end context "when saving at the parent level" do let!(:server) do Server.new(name: "staging") end let!(:filesystem) do server.filesystems.build end context "when the parent has an after create callback" do before do server.save end it "does not push the embedded documents twice" do expect(server.reload.filesystems.count).to eq(1) end end end context "when embedded documents are stored without ids" do let!(:band) do Band.create(name: "Moderat") end before do band.collection. find(_id: band.id). update_one("$set" => { records: [{ name: "Moderat" }]}) end context "when loading the documents" do before do band.reload end let(:record) do band.records.first end it "creates proper documents from the db" do expect(record.name).to eq("Moderat") end it "assigns ids to the documents" do expect(record.id).to_not be_nil end context "when subsequently updating the documents" do before do record.update_attribute(:name, "Apparat") end it "updates the document" do expect(record.name).to eq("Apparat") end it "persists the change" do expect(record.reload.name).to eq("Apparat") end end end end context "when embedded documents get marshalled" do let(:person) do Person.create end let!(:addresses) do person.addresses end let!(:dumped) do Marshal.dump(addresses) end let!(:loaded) do Marshal.load(dumped) end it "keeps the proxy extensions when remarshalling" do expect(loaded.extension).to eq("Testing") end end context "deleting embedded documents" do it "able to delete embedded documents upon condition" do company = Company.new 4.times { |i| company.staffs << Staff.new(age: 50 + i)} 2.times { |i| company.staffs << Staff.new(age: 40)} company.save company.staffs.delete_if {|x| x.age >= 50} expect(company.staffs.count).to eq(2) end end context "when substituting polymorphic documents" do before(:all) do class DNS; end class DNS::Zone include Mongoid::Document embeds_many :rrsets, class_name: 'DNS::RRSet', inverse_of: :zone embeds_one :soa, class_name: 'DNS::Record', as: :container end class DNS::RRSet include Mongoid::Document embedded_in :zone, class_name: 'DNS::Zone', inverse_of: :rrsets embeds_many :records, class_name: 'DNS::Record', as: :container end class DNS::Record include Mongoid::Document embedded_in :container, polymorphic: true end end after(:all) do Object.send(:remove_const, :DNS) end context "when the parent is new" do let(:zone) do DNS::Zone.new end let(:soa_1) do DNS::Record.new end context "when replacing the set document" do let(:soa_2) do DNS::Record.new end before do zone.soa = soa_1 end it "properly sets the metadata" do expect(zone.soa = soa_2).to eq(soa_2) end end context "when deleting the set document" do let(:soa_2) do DNS::Record.new end before do zone.soa = soa_1 end it "properly sets the metadata" do expect(zone.soa.delete).to be true end end end context "when the parent is persisted" do let(:zone) do DNS::Zone.create end let(:soa_1) do DNS::Record.new end context "when replacing the set document" do let(:soa_2) do DNS::Record.new end before do zone.soa = soa_1 end it "properly sets the metadata" do expect(zone.soa = soa_2).to eq(soa_2) end end context "when deleting the set document" do let(:soa_2) do DNS::Record.new end before do zone.soa = soa_1 end it "properly sets the metadata" do expect(zone.soa.delete).to be true end end end end end