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_atAS t1_r5 从左外posts连接comments打开comments。post_id= posts。id
它完全忽略了选择。
好的,让我们尝试加入:
Post.joins(:comments).select('posts.*, comments.title')
=> SELECT posts.*, comments.title FROM postsINNER JOIN commentsON 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 postsINNER JOIN commentsON 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_atAS t1_r5 从左外posts连接comments打开comments。post_id= posts。id