Rails: 多态模型,删除麻烦
Rails: Polymorphic model, troubles with deletion
在我的 Rails 电影数据库中,我现在添加了一个可以标记电影和演员的“标签”模型。
但是,我无法删除用于标记电影或演员之一的标签(foreign_key 约束);当我在这样的标签上调用 destroy 时,Rails 说:
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`))
电影(演员在这方面完全一样):
class Movie < ApplicationRecord
...
has_many :taggings, as: :taggable, dependent: :destroy
has_many :tags, through: :taggings
...
标签:
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
标记:
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :taggable, polymorphic: true
end
你可能在这里有点困惑。如果您有想要编辑标签的电影或演员,可以使用 has_many :tags
.
生成的 tags_ids=
setter
<%= 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
这将自动将参数中传递的数组与标记 table 和 add/create 行中的任何现有行相应地进行比较。
如果你想创建一个按钮来一个一个地“从可标记中删除标签”(可能用 ajax 增强)你想确保你实际上是从标签中删除行 table 而不是标签:
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
如果你真的想从整个系统中完全删除一个标签(Whosebug 上的 burnination 等价物)你需要在关联上设置依赖选项,以便不违反外键约束:
class Tag < ApplicationRecord
validates :name, presence: true
has_many :taggings, dependent: :destroy
# ...
end
您还应确保添加唯一索引,以确保您的标签中不会出现重复项 table:
add_index :taggings, [:tag_id, :taggable_id, :taggable_type], unique: true
和验证:
class Tagging
validates_uniqueness_of :tag_id, scope: [:taggable_id, :taggable_type]
end
在我的 Rails 电影数据库中,我现在添加了一个可以标记电影和演员的“标签”模型。 但是,我无法删除用于标记电影或演员之一的标签(foreign_key 约束);当我在这样的标签上调用 destroy 时,Rails 说:
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`))
电影(演员在这方面完全一样):
class Movie < ApplicationRecord
...
has_many :taggings, as: :taggable, dependent: :destroy
has_many :tags, through: :taggings
...
标签:
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
标记:
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :taggable, polymorphic: true
end
你可能在这里有点困惑。如果您有想要编辑标签的电影或演员,可以使用 has_many :tags
.
tags_ids=
setter
<%= 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
这将自动将参数中传递的数组与标记 table 和 add/create 行中的任何现有行相应地进行比较。
如果你想创建一个按钮来一个一个地“从可标记中删除标签”(可能用 ajax 增强)你想确保你实际上是从标签中删除行 table 而不是标签:
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
如果你真的想从整个系统中完全删除一个标签(Whosebug 上的 burnination 等价物)你需要在关联上设置依赖选项,以便不违反外键约束:
class Tag < ApplicationRecord
validates :name, presence: true
has_many :taggings, dependent: :destroy
# ...
end
您还应确保添加唯一索引,以确保您的标签中不会出现重复项 table:
add_index :taggings, [:tag_id, :taggable_id, :taggable_type], unique: true
和验证:
class Tagging
validates_uniqueness_of :tag_id, scope: [:taggable_id, :taggable_type]
end