How do I delete an embedded document in mongomapper?
Asked Answered
A

3

7

I run a sinatra application with mongomapper. I have models called Movie(Document) and Cover(EmbeddedDocument). I embed covers into movies using

@movie.covers << @cover
@movie.save

This works great.

When I hit @movies.covers, I got the array of embedded documents. But I am not able to destroy the embedded document. I tried something like this:

@movie.covers.each do |c|
c.destroy
end

NoMethodError: undefined method `destroy' for #<Cover:0xb7b20734>
 from (irb):5
 from /usr/lib/ruby/gems/1.8/gems/mongo_mapper-0.6.8/lib/mongo_mapper/associations/proxy.rb:85:in `call'
 from /usr/lib/ruby/gems/1.8/gems/mongo_mapper-0.6.8/lib/mongo_mapper/associations/proxy.rb:85:in `method_missing'
 from /usr/lib/ruby/gems/1.8/gems/mongo_mapper-0.6.8/lib/mongo_mapper/associations/proxy.rb:85:in `each'
 from /usr/lib/ruby/gems/1.8/gems/mongo_mapper-0.6.8/lib/mongo_mapper/associations/proxy.rb:85:in `send'
 from /usr/lib/ruby/gems/1.8/gems/mongo_mapper-0.6.8/lib/mongo_mapper/associations/proxy.rb:85:in `method_missing'
 from (irb):4
 from :0

How to destroy it? It would be great if someone enlightens me how to update the embedded document.

Aviation answered 20/12, 2009 at 14:37 Comment(0)
M
15

Covers are stored as an array within movie object, therefore you can do e.g.:

@movie.covers.clear
@movie.save

or if you want to be selective

@movie.covers.delete_if {|cover| cover.name == "bla"}
@movie.save
Musicianship answered 20/12, 2009 at 20:43 Comment(2)
Thanks pzol. It helped me. It would be very helpful if you temme how i can update covers.Aviation
You load the movie. The covers are an array, so you need to choose one, change its fields and then save: For example @movie = Movie.find(:first) @movie.covers[0].name = "updated name" @movie.saveMusicianship
G
1

This works if your deleting based on an attribute like a name, but if you already know the id and want to delete it, use this trick from p-rob's tubmlr post:

def destroy
@phone_number = @person.phone_numbers.find(params[:id])
@person.phone_numbers.delete_if{|phone_number| phone_number.id == @phone_number.id}
if @person.save
redirect_to @person
  else
    flash[:error] = "dag, yo."
  end
end

I really struggled with this :(

Goof answered 23/9, 2010 at 4:56 Comment(1)
What if you don't want to load the whole array into memory before deleting? Isn't there an operation that will remove it on the database side?Moratorium
P
0

here is a quick and dirty complete gist for deleting an embedded document from an association. Repeated here:

class Period
  include MongoMapper::EmbeddedDocument

  key :text, String

  embedded_in :schedule

  def to_s
    text
  end

end

class Schedule
  include MongoMapper::Document

  key :name, String

  many :periods

  def to_s
    text = "#{name}, periods: " + periods.join(', ')
  end

end

s1 = Schedule.create(:name => "Thursday",
  :periods => [
    Period.new(:text => "Morning"),
    Period.new(:text => "Afternoon"),
    Period.new(:text => "Evening")
  ])
puts s1
#Thursday, periods: Morning, Afternoon, Evening

s1.periods.delete_if{|p| p.text == 'Afternoon'}
s1.save
puts s1
# Thursday, periods: Morning, Evening
Parthinia answered 5/7, 2012 at 2:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.