1

在 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是因为 atag属于许多帖子。

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

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

谢谢!

4

2 回答 2

2

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_tag_id上的列post,并且belongs_to完全期望这一点。另一方面,has_one期望在另一post_id侧存在一个名为的列,即在您的. 但这是不可能的,因为有很多(不仅仅是一个),所以ID 不能保存在.post_tagpost_tagpostspostpost_tags

更新
关联之间的区别仅在于您提供的方法和您可以传入的选项(Rails 关联指南中解释的选项)。例如,has_onebelongs_to具有相同的方法:

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

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

has_and_belongs_to_many并且has_many可能在他们的方法上没有什么不同,但是他们可以通过的选项不同。例如,您可以传入

:dependent => :destroy

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

于 2012-02-23T14:38:21.490 回答
1

虽然我不确定在has_many :through关系的一侧和另一侧具有 a 的确切影响has_and_belongs_to_many,但我知道更正确的方法是使用这样的反转has_many :through

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

保持其他关系不变。

于 2012-02-23T07:44:44.070 回答