remove 1 HABTM association at a time

hi - i have two models, A and B, and each habtm the other

if I do

a = A.new b = B.new

a.bs << b a.bs << b a.bs << b

this creates 3 records in the join table.

Is there any way for me to remove only one of these? I can only seem to remove all of them.

thanks for any help, dino

This is exactly why I use join models and ignore has_and_belongs_to_many all together.

b = B.first # Find the b you want to remove association to. a.bs.delete(b)

From has_and_belongs_to_many doc:

collection.delete(object, …) Removes one or more objects from the collection by removing their associations from the join table.

thanks for the reply, unfortunately this deletes ALL of them from the association table. any other ideas?

thanks again, dino

Greg Donald wrote:

a.bs << b

this creates 3 records in the join table.

Is there any way for me to remove only one of these? �I can only seem to remove all of them.

This is exactly why I use join models and ignore has_and_belongs_to_many all together.

The issue here is not the presence or absence of a join model -- after all, for a simple habtm, there's no reason at all to introduce the extra class. Rather, this is a reflection of the fact that the OP is trying to do something weird. With or without a join model, there should be no reason to add b to a.bs 3 times.

To the OP: can you explain more about why you think you need this? I'm guessing your DB setup may be a bit pathological.

-- Greg Donald http://destiney.com/

Best,

dinoD wrote:

b = B.first # Find the b you want to remove association to. a.bs.delete(b)

From has_and_belongs_to_many doc:

collection.delete(object, �) Removes one or more objects from the collection by removing their associations from the join table.

thanks for the reply, unfortunately this deletes ALL of them from the association table. any other ideas?

thanks again, dino

If it does then you're doing something wrong. I just tried this in a test app and it work as advertised.

a.bs << b a.bs << b a.bs << b

This is somewhat unclear, but it appears from your code this is adding the same b three times. So yes, if you did exactly as shown all three association to that same b would be deleted.

a.bs << b1 a.bs << b2 a.bs << b3

a.bs.delete(b2) would properly delete only b2 and leaving b1 and b3. This is expected behavior. The only thing I don't like about how Rails handles this is that << will create copies of the same associations. So I typically add a unique index across the two primary keys of the join table to prevent duplicating associations. That being said, I also use has_many :through in all cases (as Greg mentioned). I basically pretend HABTM does not exist.

Umm yeah, well.. I work in genetics research and I can tell you I have this exact scenario _all the time_. Genetic pathways repeat throughout any genome, human or other. Your assumption that everyone's data is like your own is illogical.

And like I was saying, to avoid the problem I use a join model. Storing an extra integer column and having an extra class in play costs very little when compared to the headaches of having to look up join table records using multiple keys and include limit statements. It's so much easier to just say Foo.delete( 18176236 ).

Greg Donald wrote: [...]

Umm yeah, well.. I work in genetics research and I can tell you I have this exact scenario _all the time_.

And you use this sort of data model for it?

Genetic pathways repeat throughout any genome, human or other. Your assumption that everyone's data is like your own is illogical.

I'm not making any assumptions about other people's data. I am merely talking about what can and can't be modeled effectively with a particular data structure.

And like I was saying, to avoid the problem I use a join model. Storing an extra integer column and having an extra class in play costs very little when compared to the headaches of having to look up join table records using multiple keys and include limit statements. It's so much easier to just say Foo.delete( 18176236 ).

For your use case, this probably makes sense. For a simple habtm where these features are not needed, I believe it is overkill.

-- Greg Donald http://destiney.com/

Best,

thanks for all the replies. just to clarify my intent, i am associating keywords with a set of documents, and the more times a keyword is associated with particular document, the more it is weighted as being relevant to that keyword, but it must be the exact same keyword, that's why i do this:

a.bs << b a.bs << b a.bs << b

so I was NOT asking for this:

a.bs << b1 a.bs << b2 a.bs << b3

and when an association disappears, i want to remove one of the associations and one only, b/c the cardinality of duplicate associations is important for my app. I explored the idea of an increment counter, but then I have to add extra logic to the controller or model.

So ultimately, I refactored to has_many :through, and now I can just remove one of the has_many's. I realize now, too, that this makes more sense philisophically, as one of the intents of has_many :through is to give the many an equal state as a bona fide model, whereas the habtm is a cardinality-less association by design (that's my conclusion any way).

thanks for all your help!

dino

Yeah, it turns out two models that share a join model is very common.