has_many :through with has_and_belongs_to_many in Rails

后端 未结 2 1846
醉酒成梦
醉酒成梦 2021-01-27 01:05

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 indi

相关标签:
2条回答
  • 2021-01-27 01:39

    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.

    0 讨论(0)
  • 2021-01-27 01:54

    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.

    0 讨论(0)
提交回复
热议问题