【问题标题】:has_many :through with has_and_belongs_to_many in Railshas_many :通过在 Rails 中使用 has_and_belongs_to_many
【发布时间】:2012-03-13 14:45:56
【问题描述】:

在 Rails 中 - 使用 has_many :through 和 has_and_belongs_to_many 有什么效果? 考虑有两个模型 - 帖子和标签,它们具有如下所示的多对多关系:

class Tag < ActiveRecord::Base
  has_many :posts_tag
  has_and_belongs_to_many :posts
end

class Post < ActiveRecord::Base
  has_many :posts_tag
  has_many :tags,  :through => posts_tag
end

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

我使用has_and_belongs_to_many 的原因是因为tag 属于许多帖子。

我确实查看了Rails Association guide,发现他们没有提到这种情况是多对多关系。然而,我确实尝试过这个并且在 Rails 中运行它并没有产生任何行为,并且从我构建的小型测试数据库中,似乎也返回了 post.tagstag.posts 的正确结果 - 其中 post 和 @ 987654328@ 分别指的是PostTag 模型的一个实例。

这是正确的用法还是有我不知道的副作用?另外,如果它是正确的,这是 Rails 实现这一点的方式吗?

谢谢!

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 activerecord associations model-associations


    【解决方案1】:

    只有在设置多对多关联时才使用has_and_belongs_to_many(换句话说,当对方也有has_and_belongs_to_many 时)。这就是这个关联的意义。

    你应该有

    class Tag < ActiveRecord::Base
      has_many :posts_tags
      has_many :posts, :through => :post_tags
    end
    
    class PostsTag < ActiveRecord::Base
      belongs_to :tag
      belongs_to :post
    end
    
    class Post < ActiveRecord::Base
      has_many :posts_tags
      has_many :tags, :through => :posts_tags
    end
    

    注意我使用了复数,post_tags(因为这是正确的方式)。

    如果你有评论中的情况,你应该有一个

    belongs_to :post_tag
    

    在您的 Post 模型中,并且

    has_many :posts
    

    在您的 PostTag 模型中。

    你现在可能会问:“我为什么要使用belongs_to :post_tag?它不属于标签,它标签。所以,不应该我使用has_one :post_tag?”。起初这也是我的问题,但后来我发现 Rails 并不总是完全适合英语。您需要post 上的post_tag_id 列,而belongs_to 正是如此。另一方面,has_one 会期望名为post_id 的列出现在other 一侧,即您的post_tag。但是这是不可能的,因为post_tag有很多posts(不止一个),所以post的ID不能保存在post_tags中。

    更新
    关联之间的区别仅在于您提供的方法和可以传入的选项(Rails 关联指南中解释过的选项)。比如has_onebelongs_to的方法是一样的:

    association(force_reload = false)
    association=(associate)
    build_association(attributes = {})
    create_association(attributes = {})
    

    但是,例如,方法 association=create_association 暗示了关于外键应该在哪里的不同事情(就像我上面解释的那样)。

    has_and_belongs_to_manyhas_many 的方法可能没有什么不同,但是它们可以传递的选项不同。比如可以传入

    :dependent => :destroy
    

    has_many 关联上,但您不能将它传递给has_and_belongs_to_many,因为这没有意义,因为它意味着多对多关联;如果父记录被销毁,子记录仍然可以与其他记录连接,因此它们不应该被销毁。

    【讨论】:

    • 是的,我想你说“Rails 不能总是完全适合英语”的部分是我真正想要的:P 鉴于一些常见的操作正在使用 has_many :through 和 @ 987654352@,从纯粹的教学角度来看,知道这是否有任何副作用会很有趣。我知道这不是正确的使用方式。
    【解决方案2】:

    虽然我不确定在关系的一侧使用 has_many :through 并在另一侧使用 has_and_belongs_to_many 的确切效果,但我知道更正确的方法是使用反向has_many :through 像这样:

    class Tag < ActiveRecord::Base
      has_many :posts_tag
      has_many :posts,  :through => posts_tag
    end
    

    保持其他关系不变。

    【讨论】:

    • 在关系的一侧使用has_one 并在另一侧使用has_and_belongs_to_many 的副作用如何?例如在上面的例子中,如果我们说每个post 最多可以有一个tag。但是,tag 将属于许多 posts
    • 在这种情况下,您的关系有点倒退。标记has_many 帖子和帖子belongs_to 一个标签。 Post 上面会有tag_id,只允许一个标签。 has_and_belongs_to_many 将使用 has_many 不会使用的隐藏连接表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    • 2011-11-19
    相关资源
    最近更新 更多