HABTM或在Rails 3中通过模型设计有很多

时间:2011-03-11 15:49:27

标签: sql ruby-on-rails ruby-on-rails-3 model

我正在为以下目的设计认证模型。用户将拥有一组证明[A,B,C,D]。一篇文章也将有一套认证,比如[B,D]。我希望能够找到他们的认证是用户认证的某些子集(读取:任何子集)的文章。也就是说,如果文章有证书[A,B,E],它将不会被退回,但如果它有[A]或[A,D]或其他任何可以返回的罚款。实际上,我想象的方法是将user.certs与art.certs交叉,并确保结果集等于art.certs.size。我将其实现为HABTM,因为我真的不需要访问连接对象,但是我在编写逻辑时遇到了麻烦。我最终做了这样的事情:

@certs = @user.certifications.collect{|c| c.id}
Article.all(:joins=>:certifications, 
         :group=>Article.attributes_for_sql, 
         :select=>'articles.*', 
         :conditions => ['certifications.id in (?)', @certs], 
         :having=> "count(articles.id)=(select (count(article_id)) from articles_certifications where article_id = articles.id group by article_id)")

这似乎有效,但非常难看。

在任何情况下,我应该如何设计这种关系以使其尽可能简单?示例解决方案是什么样的?

感谢您提供任何帮助,我真的一直在敲打着我的头。

2 个答案:

答案 0 :(得分:0)

好的,稍微澄清了一下情况,这是我对答案的正式尝试:D

从我收集的内容来看,您需要具有用户所有认证的文章。这些认证在模型中是相同的记录,因此ID应该可以正常工作。

为什么不尝试一个简单的IN语句,如下所示:

@user_certs = @user.certifications.all(:select => "id")
Article.all(:conditions => ["certification_id IN ?", @user_certs])

这应该撤回任何与您正在查看的用户具有相同认证的文章。

我希望我能解决你的问题。

答案 1 :(得分:0)

这个想法是从查询中删除所有拥有用户没有的证书的文章。 SQL非常简单:

SELECT *
FROM articles a
WHERE NOT EXISTS
    (SELECT NULL
    FROM articles_certificates ac
    WHERE ac.article_id = a.id AND ac.certificate_id NOT IN
        (SELECT cu.certificate_id
        FROM certificates_users cu INNER JOIN users u ON cu.user_id = u.id
        WHERE u.id = #{user_id})
    )

我不是ActiveRelations查询的专家,因此我的查询非常类似于我的SQL :),抱歉

Article.joins(:certificates).
    all(:conditions => "NOT EXISTS (SELECT NULL FROM articles_certificates WHERE articles_certificates.certificate_id NOT IN ? AND articles.id = articles_certificates.article_id)", #{user.certificates})