【问题标题】:Proper way to delete has_many :through join records?删除 has_many 的正确方法:通过连接记录?
【发布时间】:2013-06-01 12:13:14
【问题描述】:
class Post < ActiveRecord::Base
  has_many :posts_tags
  has_many :tags, through: :posts_tags
end

class PostsTag < ActiveRecord::Base
  belongs_to :post
  belongs_to :tag
end

class Tag < ActiveRecord::Base
  has_many :posts_tags
  has_many :posts, through: :posts_tags
end

当 Post 被销毁时,我希望它与 Tag 的所有关联也被删除。我不想在 PostsTag 模型上运行验证。我只想删除。

我发现从 Post 模型中添加依赖关系到帖子标签可以按我的意愿工作:has_many :posts_tags, dependent: :delete_all

但是,关于该主题的文档似乎建议我应该这样做:has_many :tags, through: :posts_tags, dependent: :delete_all。当我这样做时,Tag 对象被销毁,而连接对象仍然存在。

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many

对于 has_many,destroy 将始终调用要删除的记录的 destroy 方法,以便运行回调。但是 delete 将根据 :dependent 选项指定的策略进行删除,或者如果没有给出 :dependent 选项,则它将遵循默认策略。默认策略是:nullify(将外键设置为nil),除了has_many :through,默认策略是delete_all(删除连接记录,不运行回调)。

  1. 如何才能实际使用默认策略?如果我完全离开 :dependent ,则根本不会删除任何记录。而且我不能只指出:依赖于 has_many 关系。 Rails 回来说“:dependent 选项需要 :destroy、:delete_all、:nullify 或 :restrict ({})”。
  2. 如果我没有指定 :dependent 依赖于任何一个关系,它不会像它似乎暗示的那样使 PostsTag 对象上的 post_id 无效

也许我读错了,而我发现的方法是正确的方法?

【问题讨论】:

  • 如果一个标签被多个帖子使用会怎样?如果一个帖子被删除,其他帖子将受到影响。
  • true,并且标签应该有has_many :posts, through: :posts_tags 而不是帖子,我会使用has_many :posts_tags, dependent: :destroy 删除posts_tag 并保留标签。您可以使用 rake 任务或控制台删除孤立的标签。
  • 修复了关联,谢谢。我只是想了解文档。措辞令人困惑

标签: ruby-on-rails ruby-on-rails-3


【解决方案1】:

你最初的想法:

has_many :posts_tags, dependent: :delete_all

正是你想要的。您确实想在 has-many-though 关联 :tags 上声明它,因为这会破坏所有关联的标签。您要删除的是关联本身 - 这是 PostTag 连接模型所代表的内容。

那么,为什么这些文档会说他们是做什么的呢?您误解了文档描述的场景:

Post.find(1).destroy
Post.find(1).tags.delete

第一次调用(您的场景)将简单地破坏 Post。也就是说,除非您像我建议的那样指定:dependent 策略。第二个调用是文档描述的内容。调用 .tags.delete 不会(默认情况下)实际销毁标签(因为它们是通过 has-many-through 连接的),而是连接这些标签的关联连接模型。

【讨论】:

  • 谢谢。如果出于某种模糊的原因我确实想删除与第一个帖子相关联的标签,我应该使用什么语法?
  • @MSC Tag.where(id: @post.tags).delete_all 可能是最简单的方法
猜你喜欢
  • 2015-05-06
  • 1970-01-01
  • 2016-02-19
  • 2012-10-24
  • 2011-04-29
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多