让我们看看下面的例子。我们有两个与此关联的模型
class Post < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts
end
如您所知,我们可以执行以下操作:
<%= @post.title %>
<%= @post.user.name %>
etc etc
此关联通常会生成以下查询:
SELECT * FROM `posts` WHERE `post`.`id` = 1;
SELECT * FROM `users` WHERE `user`.`id` = 15; # from @post.user
现在,如果我想选择某些特定字段(假设暂时没有关联)列出所有帖子或只显示一个帖子,我会这样做:
@posts = Post.select("id, title, slug, created_at").all()
# or
@post = Post.select("id, title, slug, created_at").find(1)
如果关联,如何为关联查询选择特定字段?换句话说,而不是
SELECT * FROM `users`
SELECT * FROM `posts` WHERE `user_id` IN ( user IDs here )
拥有
SELECT `id`, `name` FROM `users`
SELECT `id`, `user_id`, `title`, `slug` FROM `posts` WHERE `user_id` IN ( user IDs here )
答案 0 :(得分:0)
答案 1 :(得分:0)
在select
子句中检索限制其属性的单个帖子时,其行为与任何其他帖子相同,但为了能够访问用户,它应具有已选择user_id
属性。
@post = Post.select("id").first
# this post doesn't know about it's user since it has no user_id attribute
@post.user # => nil
@post = Post.select("id", "user_id").first
# this post has a user
@post.user # => #<User...>
当您检索帖子列表时,您应该解决&#39; n + 1查询问题&#39;。你可以在这里阅读http://guides.rubyonrails.org/active_record_querying.html(13个预先加载的协会)
您可以将includes
用于热切加载关联:
@posts = Post.includes(:user)
@posts.each do |post|
post.user # this will not make an extra DB query since users are already eager loaded
end
或者,如果您不需要实例化用户并希望获得特定属性,那么更好的解决方案是join
与用户并获取您需要的属性
@posts = Post.joins(:user).select("posts.id", "posts.title", "users.name AS user_name")
@posts.each do |post|
post.user_name # each post now has `user_name` attribute
end
<强>被修改强>
据我所知,使用includes
会忽略select
。您无法在此处使用select
来指定您需要的帖子或用户的哪些属性。将检索整个帖子并且整个用户将被急切加载。但是,有一种方法可以通过在belongs_to
关联中指定用户的加载属性来限制用户的加载属性。对此有一个类似的问题:ActiveRecord includes. Specify included columns
另外,请注意,Post.joins(:user)
不会返回没有用户的帖子。因此,如果可能,您需要使用.left_outer_joins
来代替所有帖子。
# works in Rails 5
Post.left_outer_joins(:user).select(...)