rails活动记录选择

时间:2011-02-01 12:53:00

标签: ruby-on-rails activerecord select include arel

问:在一个查询中选择所有帖子和相关评论,将评论关系加载到p.com中,但只从评论中选择标题

发布

#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.com中,但只从评论中选择标题:

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

=&GT;选择postsid AS t0_r0,poststitle AS t0_r1,poststext AS t0_r2,posts。{ {1}} AS t0_r3,created_atposts AS t0_r4,updated_atcomments AS t1_r0,idcomments AS t1_r1,{ {1}}。title AS t1_r2,commentstext AS t1_r3,commentspost_id AS t1_r4,comments。{{1 AS t1_r5 FROM created_at LEFT OUTER JOIN comments ON updated_atposts = commentscomments

完全忽略了选择。

好的,让我们尝试加入:

post_id

=&GT; SELECT posts。*,comments.title FROM posts INNER JOIN id ON Post.joins(:comments).select('posts.*, comments.title') posts = commentscomments

更好,但我们需要表别名--Rails不处理关系(为什么?)

post_id

=&GT; SELECT posts。*,comments.title as comments_title FROM posts INNER JOIN id ON posts = Post.joins(:comments).select('posts.*, comments.title as comments_title').first posts = commentscomments

post_id

好的,让我们试试ARel

posts

=&GT;选择idposts.first.comments.loaded? # false posts.first.comments_title # "Comment 1.1" 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 ) postsidpoststitlecomments FROM { {1}}内部加入id开启commentstitle = postscomments

相同的故事 - ActiveRecord不处理关系。

有什么建议吗?

UPD

  1. 如果这个问题没有直接的解决方案,也许有一种方法可以使用一些AR方法来转换结果查询。因为,AR使用ARel,然后在其上调用find_by_sql,然后做一些魔法,我无法找到执行的时间和中提琴:中提琴:生成的别名和加载关联。

  2. 也许有一对一关系的解决方案?

    posts = Post.select('posts.id,posts.title,comments.id,comments.title')。includes(:comment) posts.first.comment.loaded? #true

  3. =&GT;选择commentspost_id AS t0_r0,postsid AS t0_r1,postsid AS t0_r2,posts。{ {1}} AS t0_r3,titleposts AS t0_r4,textposts AS t1_r0,created_atposts AS t1_r1,{ {1}}。updated_at AS t1_r2,commentsid AS t1_r3,commentstitle AS t1_r4,comments。{{1 AS t1_r5 FROM text LEFT OUTER JOIN comments ON post_idcomments = created_atcomments

3 个答案:

答案 0 :(得分:3)

我担心我没有任何建议,因为您描述的所有场景都按预期工作。

  • :includes =&gt;急切的装载
  • :joins =&gt;不急于加载

因此,如果您希望直接加载注释,则必须使用包含,连接将永远不会有效。

接下来,由于SQL查询中使用了某些选择语法,因此需要加载。换句话说,当与includes一起使用时,将忽略您指定的选择,默认情况下将加载所有列。

我认为最近尝试添加您正在寻找的功能是in this ticket,它通过在include调用中添加except参数来解决。但它似乎没有得到任何回应。

就我个人而言,我会选择你使用includes指定的第一个例子,但是跳过select并使用了加载comment.text的事实。比我能想到的任何其他场景更好。

答案 1 :(得分:0)

您还可以通过执行以下操作来使用具有活动记录的原始SQL查询:

post_comment = Post.find_by_sql("SELECT p.*, c.title AS comment_title FROM posts p JOIN comments c ON p.id=c.post_id").first
post_comment.comment_title

有点hacky但似乎有效。 ActiveRecord还为您公开连接属性,以执行更复杂的查询。 http://apidock.com/rails/ActiveRecord/Base/connection

答案 2 :(得分:-1)

其中一个解决方案是切换到DataMapper而不是ActiveRecort。那对我而言,AR更好。 Use DataMapper instead of ActiveRecord

相关问题