1

I want to remove an element from a has_many relationship collection without destroying the element.

This works for me with this method:

current_user.flats.delete(Flat.find(7))

When I try to do a similar thing on the rails console, it destroys the whole object in the database:

irb(main):018:0> current_user.houses.delete(House.find(10))

SQL (13.4ms)  DELETE FROM "cities_houses" WHERE "cities_houses"."city_id" = ?  [["city_id", 10]]
SQL (0.8ms)  DELETE FROM "houses" WHERE "houses"."id" = ?  [["id", 10]]

As you can see, it removes the whole house object from it's own table.

What makes even less sense: It tries to remove an entry on the join table "cities_houses" using the given house_id (10) as parameter for the city_id to remove the element?

I don't get in general why it tries to update this join table. My command had nothing to do with it...

I'm using Rails version: 5.1.1 and Ruby version: 2.4.1 (x86_64-linux)

Vega180
  • 779
  • 2
  • 5
  • 22
  • if it's a has_many through relationship then it makes perfect sense that it would delete the row in a join table that defines that association. can you post your models and schema for users, cities, houses, and cities_houses? – m. simon borg Aug 01 '17 at 23:07
  • You've hit the point! It'S a has_many/bleongs_to rleationship. I just solved the problem and read your comment afterwards :) Thank you! I've posted this as an answer. But anyways, I thinks it's weird, that it doesn't throw an error, but updates other tables. Pretty dangerous in production mode... – Vega180 Aug 01 '17 at 23:40

1 Answers1

0

I found a solution to solve the problem!

This doesn't work, when dependent: :destroy is enabled.

current_user.houses.delete(House.find(10))

The solution is pretty obvious: for a has_many/belongs_to-association, you can just update the value user_id of the flat to nil. I knew this way, but what I've tried first didn't worked:

House.find(10).user_id = nil
House.find(10).save

The updated value will be changed and the change is immediately forgotten, if it is not stored in a variable.

This works:

house = House.find(10)
house.user_id = nil
house.save

Another solution, without loading the house model first:

House.where(id: 10).update_all(user_id: nil)
Vega180
  • 779
  • 2
  • 5
  • 22
  • Usually in a `has_many` `belongs_to` association doing `current_user.houses.delete(House.find(10))` would work, setting `user_id` on `house` to `null`. However if your `user` `has_many :houses, dependent: :destroy` then `current_user.houses.delete(House.find(10))` *will* destroy the `house`, which will subsequently destroy its `cities_houses` join table entries. Does your `User has_many :houses, dependent: :destroy`? If so, then you probably shouldn't be mixing that with `houses` that have `user_id = null` – m. simon borg Aug 01 '17 at 23:52
  • I get it slowly. My user `has_many :houses, dependent: :destroy` indeed. This means: The house gets destroyed when the connection is removed, am I right? So it's not a bug - it's expected behavior... Is it really not okay to have `dependent: :destroy` and `user_id = null` allowed? In my case a house is created without a `user_id`. Over time, a user can become its owner. When the user will be removed, the house should also get removed. Is it okay in this case or bad practice? – Vega180 Aug 02 '17 at 01:30
  • `House.where(id: 10).update_all(user_id: nil)` no need to load the record. – Adam Lassek Aug 02 '17 at 01:37
  • Great comment, I'll add this to my answer! – Vega180 Aug 02 '17 at 08:43