Rails HABTM - Properly removing an association
Asked Answered
T

1

54

I am developing a feature for creating specials, for a shopping website. One product can have more than one special, and obviously a special can have more than one product..

I am using a has_and_belongs_to_many relationship, so i have declared:

Product.rb

has_and_belongs_to_many :specials

Special.rb

has_and belongs_to_many :products

Now, with a product @product and a special @special, an association is created like so..

@special.products << @product

After doing this, the following is true:

@special.products.first == @product

and, importantly:

@product.specials.first == @special

When i delete the association using this

@special.products.delete(@product)

then @product is removed from specials, so @special.products.first==nil, however @product still contains @special, in other words @products.specials.first==@special

Is there any proper way, apart from writing a delete method, to do this in a single call?

Towhee answered 22/1, 2014 at 9:31 Comment(5)
And by the way, why are the backticks not turning the words into code? Sorry, this is my first post on StackoverflowTowhee
backticks only work for strings - if you have blocks of code, you should indent by 4 spacesMueller
I think it does remove the association both ways, have you tried reloading @special ?Foreordain
xlembouras is correct. @special.products.delete(@product) actually does remove the association on both sides, as it deletes the record in the join table (ie product_specials). Try @product.reload.specials or telling .specials to re-fetch the join table records by passing it true, like so @product.specials(true). See here.Mouthwatering
You also can use three backticks at before the first line, and three at the last time. If you wanna force color coding you can write it after the first three backticks like so '''ruby \n def myCode end \n '''Nunuance
M
92

According to the Rails documentation:

collection.delete(object, …)

Removes one or more objects from the collection by removing their associations from the join table. This does not destroy the objects.

Brilliant reference here for you

You can use:

product = Product.find(x)
special = product.specials.find(y)

product.specials.delete(special)

This creates ActiveRecord objects for both the object you're trying to remove, which gives clear definition to the function

collection.clear

Removes all objects from the collection by removing their associations from the join table. This does not destroy the objects.

In this example:

product = Product.find(x)

product.specials.clear
Mueller answered 22/1, 2014 at 9:43 Comment(1)
Should mention that calling delete on a has_and_belongs_to_many will automatically commit the removal to the database by deleting the row from the join table.Legumin

© 2022 - 2024 — McMap. All rights reserved.