Paul Harker
Paul Harker

Reputation: 166

Deleting a record through a join table

I'm sure this has been answered hundreds of times, but I have searched and tried 100 things this morning so I am just going to ask the question. Feel free to just link me to another post...

I have 3 models: Notes, Tags, NoteTags (join)

Notes have many tags, tags have many notes; I'm trying to destroy a Note, the NoteTag link is being destroyed but the Tags remain.

Models:

class Note < ApplicationRecord
  has_many :note_tags
  has_many :tags, -> { uniq }, through: :note_tags, dependent: :destroy
end

class Tag < ApplicationRecord
  has_many :note_tags
  has_many :notes, through: :note_tags, dependent: :destroy
end

class NoteTag < ApplicationRecord
  belongs_to :note
  belongs_to :tag
end

So, obviously if the Tag still has a different note that has it, I don't want it to be deleted.. but if it's no longer featured in the note_tag table, it should be removed...

Is there any way of doing this?!

Thanks

Upvotes: 0

Views: 182

Answers (1)

Pablo
Pablo

Reputation: 3005

You could destroy orphan tags after destroying the note.

def destroy
  @note = Note.find_by(id: params[:id])
  if @note
    @note.destroy_with_tags
  end
end

def destroy_with_tags
  oldtag_ids = tag_ids
  destroy
  Tag.find(oldtag_ids).each do |tag|
    tag.destroy if tag.notes == []
  end
end

There may be other more efficient approach, in case the number of tags is big.

Second approach (currently not working)

Use the normal destroy and add a callback to destroy orphan tags. This option does not work, but might work with some changes I could not test.

class Note << ApplicationRecord
  before_destroy :old_tags
  after_destroy :destroy_orphan_tags

  def old_tags
    @oldtag_ids = tag_ids
  end

  def destroy_orphan_tags
    #Destroy tags that were associated to this note, if there are no more notes
    Tag.find(@oldtag_ids).joins(:note_tags).group('tags.id').having("count (*) = 0").destroy_all
  end
end

Upvotes: 1

Related Questions