12

我有一个有多个Post模型的应用程序,每个模型都有belongs_to一个User模型。当这些帖子发布时,PublishedPost会创建一个模型来表示belongs_to相关Post模型。

我正在尝试构建一个 ActiveRecord 查询以查找与用户名匹配的已发布帖子,然后获取这些已发布帖子的 ID,但是当我pluck在急切加载我的关联和搜索后尝试使用该方法时出现错误他们用where方法。

这是我的控制器的(部分):

class PublishedPostsController < ApplicationController

  def index
    ar_query = PublishedPost.order("published_posts.created_at DESC")

      if params[:searchQuery].present?
        search_query = params[:searchQuery]
        ar_query = ar_query.includes(:post => :user)
                           .where("users.name like ?", "%#{search_query}%")
      end

    @found_ids = ar_query.pluck(:id)

  ...

  end

end

调用该pluck方法时,我得到以下信息:

ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'users.name' in 'where clause': SELECT id FROM `published_posts`  WHERE (users.name like '%Andrew%') ORDER BY published_posts.created_at DESC

我可以得到我正在寻找的结果

@found_ids = ar_query.select(:id).map{|r| r.id}

但我宁愿使用pluck它,因为它似乎是更清洁的方式。不过,我不知道为什么它不起作用。有任何想法吗?

4

3 回答 3

11

您需要并且应该这样做joins而不是在includes这里。

这两个函数非常相似,只是joins查询结果中不返回 from 的数据,而 an 中的数据includes是。

在这方面,includes并且pluck是一种对立的。一个说尽可能把所有数据都还给我,而另一个说只给我一点点。

由于您只需要少量数据,因此您想做joins. (奇怪的是,这似乎有点对立仍然有效,但在这种情况下select,您需要消除歧义。)id

在控制台中尝试一下,您会发现这includes会导致查询看起来像这样:SELECT "posts"."id" as t0_ro, "posts"."text" as t0_r1, "users"."id" as t1_r0, "users"."name" as t1_r1 ...当您添加一条pluck语句时,所有那些疯狂的 tx_ry 列都会消失,并被您指定的任何内容替换。

我希望这会有所帮助,但如果不是,也许这个 RailsCast 可以。它在 5 分钟左右进行解释。

http://railscasts.com/episodes/181-include-vs-joins

于 2013-01-23T20:18:20.603 回答
9

如果您通过搜索“rails pluck ambiguous column”来到这里,您可能想知道您可以替换query.pluck(:id)为:

query.pluck("table_name.id")
于 2013-12-30T20:44:50.903 回答
0

即使没有 pluck 调用,您的查询也不会像它所写的那样工作。

原因是,您的 WHERE 子句包括引用用户表的文字 SQL,Rails 没有注意到并决定使用多个查询并加入内存( .preload() )而不是加入数据库级别( .eager_load() ):

SELECT * from published_posts WHERE users.name like "pattern" ORDER BY published_posts.created_at DESC
SELECT * from posts WHERE id IN ( a_list_of_all_post_ids_in_publised_posts_returned_above )
SELECT * from users WHERE id IN ( a_list_of_all_user_ids_in_posts_returned_above )

3 个查询中的第一个失败,这是您得到的错误。

要强制 Rails 在此处使用 JOIN,您应该使用显式的 .eager_load() 而不是 .includes(),或者添加一个 .references() 子句。

除此之外,@Geoff 回答的内容是,您实际上并不需要 .includes() ,而是需要 .joins()。

于 2014-11-29T22:51:48.370 回答