Read more

Don't forget: Automatically remove join records on has_many :through associations

Thomas Klemm
April 17, 2015Software engineer

Bad

# Given the following models

class Image < ActiveRecord::Base
  has_many :album_images
  has_many :albums, through: :album_images
end

class Album < ActiveRecord::Base
  has_many :album_images
  has_many :images, through: :album_images
end

# Join model
class AlbumImage < ActiveRecord::Base
  belongs_to :album
  belongs_to :image
end

Destroying a record in this setup will only remove the record itself, and leave orphaned join records behind.

image = Image.last
image.destroy # removes only the `image` record,
              # but none of the associated `album_image` join records

Good

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

By adding the :dependent => :destroy option to the has_many :through associations, the join records will be removed when an image or an album is destroyed.

class Image < ActiveRecord::Base
  has_many :album_images
  has_many :albums, through: :album_images, dependent: :destroy
end

class Album < ActiveRecord::Base
  has_many :album_images
  has_many :images, through: :album_images, dependent: :destroy
end

Note: the associated record with through (the albums in the example) will never be deleted by specifying dependent: :destroy, only the join records. Thus the following example will have the same effect as the above and is more explicit:

class Image < ActiveRecord::Base
  has_many :album_images, dependent: :destroy
  has_many :albums, through: :album_images
end
Posted by Thomas Klemm to makandra dev (2015-04-17 14:18)