Q:一个查询中选择所有帖子和相关评论,将评论关系加载到p.comments中,但从评论中只选择标题
邮政
#db
create_table :posts do |t|
t.string :title
t.text :text
t.timestamps
end
#modlel
class Post < ActiveRecord::Base
has_many :comments
end
评论
#db
create_table :comments do |t|
t.string :title
t.text :text
t.integer :post_id
t.timestamps
end
#model
class Comment < ActiveRecord::Base
belongs_to :post
end
我需要什么:在一个查询中选择所有帖子和相关评论并将评论关系加载到 p.comments 中,但仅从评论中选择标题:
posts = Post.includes(:comments).select("posts.*, comments.title")
posts.each do |p|
puts(p.title)
puts(p.text)
p.comments.each do |c|
puts(c.title)
end
end
如果第一部分由 .includes 完成:
posts = Post.includes(:comments).select('posts.*, comments.title')
posts.first.comments.loaded? # true
=> 选择posts
。id
作为 t0_r0, posts
. title
作为 t0_r1, posts
. text
作为 t0_r2, posts
. created_at
作为 t0_r3, posts
. updated_at
作为 t0_r4, comments
. id
作为 t1_r0, comments
. title
作为 t1_r1 comments
,。text
作为 t1_r2 comments
,。post_id
作为 t1_r3, comments
。created_at
作为 t1_r4, comments
。updated_at
AS t1_r5 从左外posts
连接comments
打开comments
。post_id
= posts
。id
它完全忽略了选择。
好的,让我们尝试加入:
Post.joins(:comments).select('posts.*, comments.title')
=> SELECT posts.*, comments.title FROM posts
INNER JOIN comments
ON comments
。post_id
= posts
。id
更好,但我们需要表别名——Rails 不处理关系(为什么?)
posts = Post.joins(:comments).select('posts.*, comments.title as comments_title').first
=> SELECT posts.*, comments.title as comments_title FROM posts
INNER JOIN comments
ON comments
。post_id
= posts
。id
posts.first.comments.loaded? # false
posts.first.comments_title # "Comment 1.1"
好的,让我们试试 ARel
p = Post.arel_table
c = Comment.arel_table
posts = Post.find_by_sql(
p.join(c).on(c[:post_id].eq(p[:id])) \
.project(p[:id],p[:title],c[:id],c[:title]).to_sql
)
=> 选择posts
。id
, posts
. title
, comments
. id
, comments
. title
从posts
内部连接comments
开始comments
。post_id
= posts
。id
同样的故事——ActiveRecord 不处理关系。
有什么建议么?
UPD
如果这个问题没有直接的解决方案,也许有一种方法可以使用一些 AR 方法来转换结果查询。因为,AR 使用 ARel,然后在其上调用 find_by_sql,然后做一些魔术,我无法找到它的执行时间和执行时间,以及中提琴:生成别名和加载关联。
也许有一对一关系的解决方案?
帖子 = Post.select('posts.id,posts.title,comments.id,comments.title').includes(:comment) posts.first.comment.loaded? #真的
=> 选择posts
。id
作为 t0_r0, posts
. title
作为 t0_r1, posts
. text
作为 t0_r2, posts
. created_at
作为 t0_r3, posts
. updated_at
作为 t0_r4, comments
. id
作为 t1_r0, comments
. title
作为 t1_r1 comments
,。text
作为 t1_r2 comments
,。post_id
作为 t1_r3, comments
。created_at
作为 t1_r4, comments
。updated_at
AS t1_r5 从左外posts
连接comments
打开comments
。post_id
= posts
。id