【问题标题】:HABTM or Has Many Through Model design in Rails 3HABTM 或在 Rails 3 中有很多贯穿模型设计
【发布时间】:2011-03-11 15:49:26
【问题描述】:

我正在为以下目的设计一个认证模型。用户将拥有一组证书,例如 [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)")

这似乎可行,但非常难看。

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

感谢您的帮助,我真的一直在用头撞墙。

【问题讨论】:

  • 为什么选择HABTM?哪两个模型具有多对多关系?我只看到两个一对多的关系,你想在其中建立你的交集。
  • 另外,您的第一行可能会重写为:@certs = @user.certifications.all(:select => "id") 这样,您只需从数据库,而不是整个对象。
  • 证书是静态的。所以大约有 20 个。因此,有很多用户拥有金融认证,因此金融认证将拥有很多用户,因此调用 Certification.find_by_name('finance').users 将获得所有拥有它的用户。文章也是如此。如果您调用@article.certifications,您将获得所有证书,如果您调用@cert.articles,您将获得所有需要该证书的文章。编辑:我当然愿意接受其他建议。
  • 好的,有道理。这部分有点令人困惑:“我希望能够找到他们的认证是用户文章的某个子集(阅读:任何子集)的文章。”用户也与文章相邻?
  • 啊,我的错。那应该是证书。在原来的q中改变了它。感谢您找到它。

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


【解决方案1】:

好的,稍微澄清一下情况,这是我的官方尝试回答,:D

根据我收集到的信息,您需要具有用户拥有的所有认证的文章。不同型号的认证记录相同,因此 ID 应该可以正常工作。

为什么不尝试一个简单的 IN 语句,像这样:

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

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

我希望我已经理解了你的问题。

【讨论】:

  • 嗯。这过于简单化了。仅当用户拥有文章拥有的所有证书而不是任何一个证书时,才应退回文章。此外,文章通过 HABTM 连接到认证(即连接表),因此 Certification_id 不是有效列。
  • 糟糕,抱歉,我指的是连接表,而不是文章。
  • 参见上面的解决方案。这是一个可行的解决方案,它实在是太恶心了。
【解决方案2】:

这个想法是从查询中删除所有具有用户没有证书的文章。 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})

【讨论】:

    猜你喜欢
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多