has_many :through with has_and_belongs_to_many in Rails

拜拜、爱过 提交于 2019-12-02 12:09:34

问题


In Rails - what is the effect of using has_many :through with has_and_belongs_to_many? Consider having two models - Posts and Tags which have a many-to-many relationship as indicated below:

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

The reason I use has_and_belongs_to_many is because a tag belongs to many posts.

I did look into the Rails Association guide and see that they don't mention this case for a many-to-many relationship. I, however, did try this and running it in Rails didn't yield any behavior and from the small test database that I built, also seemed to return the correct results for post.tags and tag.posts - where post and tag refer to an instance of the Post and Tag models respectively.

Is this correct usage or does it have any side affects that I am not aware of? Also, if it is correct, is this the Rails way of achieving this?

Thanks!


回答1:


You use has_and_belongs_to_many only when you're setting a many-to-many association (in other words, when the other side also has has_and_belongs_to_many). That is the meaning of this association.

You should have

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

Notice that I used the plural, post_tags (because this is the correct way).

If you have the situation like in your comment, you should have a

belongs_to :post_tag

in your Post model, and

has_many :posts

in your PostTag model.

You may ask now: "Why should I use belongs_to :post_tag? It doesn't belong to a tag, it has a tag. So, shouldn't I use has_one :post_tag?". This was also my question at first, but then I figured that it Rails cannot always perfectly suit the english language. You need the post_tag_id column on your post, and belongs_to expects exactly that. On the other hand, has_one would expect that a column named post_id is present on the other side, that is in your post_tag. But this would be impossible, because post_tag has many posts (not only one), so the post IDs cannot be held in post_tags.

Update:
The difference between associations are only in the methods you are provided and options you can pass in (the one explained in the Rails guide on associations). For example, has_one and belongs_to have the same methods:

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

But, for example, methods association= and create_association imply different things concerning where the foreign key should be (like I explained above).

has_and_belongs_to_many and has_many probably don't have anything different in their methods, but they differ in the options you can pass. For example, you can pass in

:dependent => :destroy

on the has_many association, but you can't pass it to a has_and_belongs_to_many, because that wouldn't make sense, since it implies a many-to-many association; if a parent record is destroyed, child records can still be connected with other records, so they shouldn't also be destroyed.




回答2:


While I'm not sure of the exact effects of having a has_many :through on one side of a relationship and a has_and_belongs_to_many on the other side, I do know that the more correct way, would be to use a reversed has_many :through like so:

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

Keeping the other relationships the same.



来源:https://stackoverflow.com/questions/9408931/has-many-through-with-has-and-belongs-to-many-in-rails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!