我有一个应用程序,其中包含许多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
中的数据返回。
在这方面,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
如果你通过搜索"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()。