Rails: Polymorphic model, troubles with deletion

In my Rails movie database, I have now added a "Tag" model that can tag both movies and actors. However I am not able to delete a tag that is used to tag either one of a movie or an actor (foreign_key constraint); when I call destroy on such a tag, Rails says:

Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`newmovie_development`.`taggings`, CONSTRAINT `fk_rails_e21d88485b` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`))

Movie (actor is exactly the same in this regard):

class Movie < ApplicationRecord
    ...
    has_many :taggings, as: :taggable, dependent: :destroy
    has_many :tags, through: :taggings
    ...

Tag:

class Tag < ApplicationRecord
    validates :name, presence: true

    has_many :taggings
    has_many :movies, through: :taggings, :source => 'taggable', :source_type => 'Movie'
    has_many :actors, through: :taggings, :source => 'taggable', :source_type => 'Actor'
end

Tagging:

class Tagging < ApplicationRecord
    belongs_to :tag
    belongs_to :taggable, polymorphic: true
end

You're probably a bit confused here. If you have a movie or actor that you want to be able to edit the tags for you can use the tags_ids= setter generated by has_many :tags.

<%= form_with(model: @actor) do |form| %>
  <div class="field">
    <%= form.label :tags_ids, 'Tags' %>
    <%= form.collection_checkboxes :tag_ids, Tag.all, :id, :name %>
  </div>
<% end %>
class ActorsController < ApplicationController
  before_action :set_actor, except: [:new, :create, :index]

  def update
    if @actor.update(actor_params)
      redirect_to @actor, success: 'Actor updated' 
    else
      render :new
    end
  end

  private

  def set_actor
    @actor = Actor.find(params[:id])
  end
  
  def actor_params
    params.require(:actor)
          .permit(:foo, :bar, tag_ids: [])
  end
end

This will automatically diff the array passed in the parameters against any existing rows in the taggings table and add/create rows accordingly.

If you want to create a button to "remove tags from a taggable" one by one (perhaps enhanced with ajax) you want to make sure you're actually deleting rows from the taggings table and not tags:

module Actors
  class TagsController < ApplicationController
    # DELETE /actors/1/tags/2
    def destroy
      @tagging = @actor.taggings.find_by!(tag_id: params[:id])
      @tagging.destroy
    end

    private

    def set_actor
      @actor = Actor.find(params[:actor_id])
    end
  end
end

If you do actually want to remove a tag completly from the entire system (the equivilent of burnination here on Stackoverflow) you need to setup the dependent option on the assocation so that the foreign key constraint is not violated:

class Tag < ApplicationRecord
  validates :name, presence: true
  has_many :taggings, dependent: :destroy
  # ...
end

You should also make sure to add a unique index to ensure that you don't get duplicates in your taggings table:

add_index :taggings, [:tag_id, :taggable_id, :taggable_type], unique: true

And a validation:

class Tagging
  validates_uniqueness_of :tag_id, scope: [:taggable_id, :taggable_type]
end