【问题标题】:Rails ActiveRecord finding questions by tag in named scopeRails ActiveRecord 在命名范围内按标签查找问题
【发布时间】:2013-10-12 19:09:11
【问题描述】:

我想要相当于 SO 按标签搜索,所以我需要一个 exists 查询,但我仍然需要在所有标签上左连接。我已经尝试了几种方法,但我没有想法。

Qustion - Tag 关系通过has_and_belongs_to_many 两种方式(即我有一个 QuestionTags 连接器表)

例如

Question.join(:tags).where('tag.name = ?', tag_name).includes(:tags)

我希望这能满足我的需要,但实际上它只是将 includesjoin 混合在一起,我最终得到的基本上是一个内部连接。

Question.includes(:tags)
   .where("exists (
               select 1 from questions_tags 
                where question_id = questions.id 
                  and tag_id = (select id 
                                  from tags 
                                 where tags.name = ?))", tag_name) 

这会获取正确的结果,但是 a) 真的很难看,并且 b) 给出了弃用警告,因为它似乎又将 includesjoin 混淆了:

弃用警告:您似乎急于加载表(一个 of: questions, tags) 在字符串 SQL sn ippet 中引用。为了 示例:

Post.includes(:comments).where("comments.title = 'foo'")

请注意,我正在尝试将这些写为命名范围。

如果问题不清楚,请告诉我。提前致谢。

【问题讨论】:

  • 说实话我很困惑为什么内部连接对你来说不够好,你能详细说明一下为什么加入标签对你不起作用吗?
  • @EdgarsJekabsons 因为我需要显示带有特定标签的所有问题的列表,但在该列表中我仍然需要显示每个问题的所有标签,避免 N+1 查找。例如。单击上面的sql 标签以查看满足我需要的 SO 页面。只有内部连接,页面只会在每个问题下显示sql 标签。

标签: sql ruby-on-rails sqlite activerecord arel


【解决方案1】:

好的,知道了。我知道没有内置的语法来做到这一点。我以前使用过替代方法,您可以这样做:

Question.include(:tags).where("questions.id IN (
#{ Question.joins(:tags).where('tags.name = ?', tag_name).select('questions.id').to_sql})")

您也可以将此子查询加入到您的问题表中,而不是使用 IN。或者,如果您不反对添加 gem 并且您正在使用 Postgres,请使用此 gem。 它为高级查询提供了非常简洁的语法。

【讨论】:

  • 谢谢,这可行,但我再次收到弃用警告,有什么办法可以解决这个问题吗?
  • 是的,没有区别。即使使用不相关的包含,我实际上也会收到此警告,例如Question.tagged("sql").includes(:votes)。在我看来,rails 中有一个错误,我在任何同时具有 joinincludes 的查询中都遇到了同样的问题。
  • 抱歉没有克隆任何 Rails 4 项目,所以不能自己玩。也许尝试在 Rails Github repo 中提交票证?
【解决方案2】:

使用preload 代替includes

Question.preload(:tags).where("exists ....

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多