如何在Rails中定义多个has_and_belongs_to_many?

时间:2012-03-29 17:09:31

标签: ruby-on-rails

我有两个模型:User,Article

用户可能喜欢或不喜欢很多文章,很多用户都喜欢或不喜欢文章。所以我需要在它们之间建立多对多的关系。

在rails中,我想我需要使用has_and_belongs_to_many ..

我认为代码的结构如下:

class User
    has_and_belongs_to_many :liked_articles
    has_and_belongs_to_many :disliked_articles
end

class Article
    has_and_belongs_to_many :liking_users
    has_and_belongs_to_many :disliking_users
end

当然,上面的代码不起作用。

但我不知道正确的代码是什么。谁能帮帮我?

更新:

我想出了这样的代码:

class User
    has_and_belongs_to_many :liked_articles, :class_name => 'Article', :join_table => 'articles_users_like', :uniq => true
    has_and_belongs_to_many :disliked_articles, :class_name => 'Article', :join_table => 'articles_users_dislike', :uniq => true
end

class Article
    has_and_belongs_to_many :liking_users, :class_name => 'User', :join_table => 'articles_users_like', :uniq => true
    has_and_belongs_to_many :disliking_users, :class_name => 'User', :join_table => 'articles_users_dislike', :uniq => true
end

我认为它会奏效。

但正如Peter Sobot和Jon McIntosh所说,现在有了很多,通过更优先。你能告诉我为什么吗? 后者在逻辑上比has_and_belongs_to更清晰?

2 个答案:

答案 0 :(得分:4)

这些关联方法与模型相关联。除非您拥有Liking_UserDisliking_User模型,否则这显然不起作用。除此之外,我相信你会以错误的方式去做。

让我们暂时解决这个问题。您有UserArticleArticle Users需要具有不喜欢喜欢的功能,对吗?我将把它想象成类似于SO / Reddit信誉系统,并假设User可以喜欢不喜欢 Article一旦。为此,我将创建一个单独的投票模型,称为Votes,并将其与has_many, :through关联结合在一起。

<强> User.rb

  class User < ActiveRecord::Base
     has_many :votes
     has_many :articles, :through => :votes
   end

<强> Article.rb

  class Article < ActiveRecord::Base
     has_many :votes
     has_many :users, :through => :votes
  end

<强> Vote.rb

  class Vote < ActiveRecord::Base
     belongs_to :user
     belongs_to :article
  end

现在已经建立了这些关联,模型将在数据库中查找几个字段。结构看起来应该是这样的:

Users
+----+-----------+
| id | user_name | 
+----+-----------+    

Articles
+----+--------+
| id |  title |
+----+--------+

Votes
+----+----------+------------+-------+
| id |  user_id | article_id | value |
+----+----------+------------+-------+

这通过为模型提供ID来引用来完成关联。现在,您可以在创建投票条目时见证rails魔术......

class ArticlesController < ApplicationController
  def like
    @article = Article.find(params[:article_id])
    @article.votes.create(:user_id => current_user, :value => 1)

    respond_to do |format|
      if @article.save
        format.html { redirect_to @article, notice: 'Article was successfully liked.' }
        format.json { head :no_content }
      else
        format.html { redirect_to @article, notice: 'Article was unsuccessfully liked.' }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end

  end
end

编辑:根据您的评论,has_and_belongs_to_manyhas_many :through关系非常相似......您有两个模型和一个连接表来保存参考数据。两者之间的区别在于has_many :through需要第三个模型,它与关系之间进行交互(比如说,用户/文章/投票)。

更广泛推荐has_many :through的原因是它更灵活,而且与后者相比,你可以获得更多的工作。在您的情况下,您必须创建此关系,因为您需要第三个模型来计算您的投票。

您现在关注的逻辑是建立一个主体来创建四个模型,并且需要根据用户想要采取的操作更新特定模型。这绝对不是轨道(或任何逻辑)的做事方式。保持简单。

Ruby on Rails Guides: A Guide to Active Record Associations

答案 1 :(得分:3)

has_and_belongs_to_many现在被认为有些过时了 - 在这种情况下你可能想要使用has_many :through。考虑使用一个表进行“投票”并做类似的事情:

class User < ActiveRecord:Base
    has_many :votes
    has_many :articles, :through => :votes
end

class Article < ActiveRecord:Base
    has_many :votes
    has_many :users, :through => :votes
end

class Vote < ActiveRecord:Base
    belongs_to :article
    belongs_to :user
end

然后你可以在vote添加一个“sign”字段,以显示它是upvote还是downvote,然后对其进行过滤。