Question

I have a collection class called MySet:

class MySet
  include DataMapper::Resource

  property :id, Serial
  has n, :my_elements, :through => Resource

  def add integer
    unless my_elements.first(:integer => integer)
      my_element = MyElement.create :integer => integer
      my_elements << my_element
      my_elements.save
    end
    self
  end

  def has_integer? integer
    !my_elements.first(:integer => integer).nil?
  end

  def delete integer
    if has_integer? integer
      my_elements.first(:integer => integer).destroy
      my_elements.save
    end
    self
  end

  def size
    my_elements.size
  end
end

and an element class called MyElement:

class MyElement
  include DataMapper::Resource

  property :id, Serial
  property :integer, Integer
end

I want to be able to add and delete elements to and from MySet. However, the following spec:

describe MySet do
  subject do
    MySet.create
  end

  it "adds and deletes" do
    subject.add 1
    subject.delete 1
    subject.size.should == 0
  end
end

fails with:

Failure/Error: subject.size.should == 0
expected: 0
got: 1 (using ==)

This is similar to the problem described in DataMapper has n through Resource DELETE (Remove from association) not working except that MyElement does not specify an association with MySet. However, I think the solution in that post is what I am using and it does not appear to work.

Was it helpful?

Solution

Take a look at the Collection documentation:

http://rubydoc.info/github/datamapper/dm-core/master/DataMapper/Collection

http://rubydoc.info/github/datamapper/dm-core/master/DataMapper/Associations/ManyToMany/Collection

I think some of the things you're doing are extraneous, and MyElement.create should probably be MyElement.first_or_create but more importantly, the part where you destroy one of the MyElement's is not quite right. It seems like what you're trying to do is remove it from the "my_elements" collection, so you should find it, and then "delete" it from the collection:

def delete integer
  element = my_elements.first(:integer => integer)
  my_elements.delete(element)
  self
end

(destroying it may also be part of what you're trying to do, and you can do that separately).

Just destroying it like you were doing may actually work (I'm not sure), but you'd probably have to reload the resource in your test to see the updated size:

subject.reload
subject.size.should == 0
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top