使用Rails查询过滤has_many到

时间:2017-02-03 16:06:36

标签: ruby-on-rails activerecord

我对RoR有一个关于多对多关系的简单问题(has_many through:)。所以我有一个Tweet模型,它有很多Tag,反之亦然。

您有一个索引操作和视图,您可以在其中显示带有标记的所有推文,但您也可以按标记进行过滤。还有一个小细节,Tweet可以没有标签。

所以,如果我做这样的事情:

Tweet.includes(:tags).where(tags: { name: #2017 })

如果您再进行过滤,那么您只会获得已过滤的标记,但不会获得Tweet所有标记。 F.E.如果Tweet标记有#2017, #2016, #2015,那么您最终只会在视图中获得#2017

所以你可以通过做这样的事情解决问题:

Tweet.joins(:tags).where(tags: { name: #2017 })

然后,您将获得每条推文的所有标签。

但问题是,如果索引页面没有过滤器,我希望所有推文都显示,没有标签的事件。

当然你可以做一个黑客,比如检查标签参数是否存在做Tweet.joins否则做Tweet.includes

有没有办法在1个查询中执行此操作并且没有黑客攻击?这也是背后的机制。我理解includes or LEFT OUTER JOIN背后的逻辑,因为它只是在您的中间表中映射tweet_id和'tag_id',然后将此ID转换为Tag表,当您有where之类的内容时查询提到上层。但是,为什么INNER JOIN让我给所有标签,给我提问。

感谢您的回答。

1 个答案:

答案 0 :(得分:2)

因为includes在您查询

时执行了预先加载
Tweet.includes(:tags).where(tags: {name: "2017"})

它急切地将带有标签名称的所有推文加载为2017. Tweet.tags将不会再次运行数据库查询,并且只有一个标记值。

但是在加入的情况下

Tweet.joins(:tags).where(tags: {name: "2017"})

它进行了内部连接,并且只查找那些标签和标签名称为2017的推文。在执行Tweet.tags时找到推文后,它再次运行数据库查询以找到所有相关标签你想要的结果。