27

Is it true that HABTM relationships do not support the :dependent option?

class Person < ActiveRecord::Base
  has_and_belongs_to_many :posts, :dependent => :destroy
end

I am trying rails edge.

Wes Foster
  • 8,770
  • 5
  • 42
  • 62
Nick Vanderbilt
  • 36,724
  • 29
  • 83
  • 106
  • As an exercise, I recommend reading this API part titled `Deleting from associations`, specially in the part `What gets deleted?`. That made me understand why and what's happening behind https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many – lucasarruda Jul 25 '18 at 15:54

3 Answers3

87

If you want to keep to the simple has_and_belongs_to_many association, you could add this:

class Person < ActiveRecord::Base
  has_and_belongs_to_many :posts
  before_destroy { posts.clear }
end

Which will clear the join table of all entries of that person. Note: This only removes records from the join table, it does not destroy the posts (which makes sense if it is a bi-direction has_and_belongs_to_many because the post might be referenced by other persons).

But guessing from your names (Person and Post) I would assume that you can probably get away with a Person has_many :posts and a Post belongs_to :person in which case you can use the :dependent => :destroy on the has_many association.

Matt Connolly
  • 9,757
  • 2
  • 65
  • 61
  • 1
    Could you please add how you would implement a `dependent: :destroy` action on a **bi-directional** `has_and_belongs_to_many` relationship which links to the **same model**? – JJD Feb 01 '13 at 17:22
  • 4
    I'm not sure if the syntax was ever originally like this answer, but I know in rails 4 it is supposed to be `before_destroy { posts.clear }` – mkralla11 Jul 25 '13 at 17:05
  • also you could use this to get the whole destroy effect `after_destroy do User.find(:all, :uniq => true, :joins => :posts, :conditions => 'posts.id is NULL').each(&:destroy) end` but might as well use has_many through at that point. – Xitcod13 Mar 15 '14 at 16:42
  • 23
    I found that i don't need to do `before_destroy { posts.clear }` in rails 4.2.0 (postgresql). Rails deletes relationship by default (it doesn't delete related record, post in this example). – Fatih Feb 10 '15 at 13:34
  • 5
    Nice tip Faith. has_and_belongs_to_many continues to delete the associations in rails 5.0.0beta2 – pctj101 Feb 20 '16 at 12:57
  • 1
    @Fatih comment need to be an answer! – abhishek77in Feb 13 '17 at 12:25
20

Yep, It doesn't support it. See the docs. Generally habtm is meant only for very very simple cases and if you start needing more complex things you should switch to has_many :through.

Jakub Hampl
  • 39,863
  • 10
  • 77
  • 106
5

Try this:

class Person < ActiveRecord::Base
  has_and_belongs_to_many :posts
  before_destroy do
    posts.each { |post| post.destroy }
  end
end

You don't need to posts.clear as Rails 4.2+ handles this already.

moeabdol
  • 4,779
  • 6
  • 44
  • 43
  • 3
    This is the correct answer. Rails 4.2+ and 5+ both will destroy association table as soon as you destroy the HABTM association. – lucasarruda Jul 25 '18 at 15:47