活动记录:不能在"where"子句之后使用"pluck"与急切加载的关联



我有一个应用程序,其中包含许多Post模型,每个模型belongs_to User模型。发布这些帖子时,将创建一个belongs_to相关Post模型的PublishedPost模型。

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

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

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,因为它似乎是更清洁的方式。不过,我不知道为什么它不起作用。有什么想法吗?

你需要而且应该做joins而不是在这里includes

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

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

由于您只需要少量数据,因此您希望执行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

如果你通过搜索"rails ppick ambigous column"来到这里,你可能想知道你可以用以下方式替换query.pluck(:id)

query.pluck("table_name.id")

即使没有 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() 而不是 .include(),或者添加 .references() 子句。

除此之外,@Geoff回答的内容仍然存在,您在这里实际上不需要 .include(),而是 .joins()。

相关内容

  • 没有找到相关文章

最新更新