ruby-on-rails - rails 事件记录选择

标签 ruby-on-rails activerecord select include arel

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 AS t0_r0, posts . title AS t0_r1, posts . text AS t0_r2, posts . created_at AS t0_r3, posts . updated_at AS t0_r4,comments . id AS t1_r0, comments . title AS t1_r1, comments . text AS t1_r2,comments . post_id AS t1_r3,comments . created_at AS t1_r4,comments . updated_at AS t1_r5 来自 posts左外连接comments开启 comments . post_id = posts . id
它完全忽略了选择。

好的,让我们尝试加入:
Post.joins(:comments).select('posts.*, comments.title')

=> 选择帖子。*,评论。标题来自 posts内连接comments开启 comments . post_id = posts . id
更好,但我们需要表别名——Rails 不处理关系(为什么?)
posts = Post.joins(:comments).select('posts.*, comments.title as comments_title').first

=> 选择帖子。*,comments.title 作为comments_title FROM posts内连接comments开启 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 并执行一些魔术,我无法找到它的执行时间和执行时间,以及 viola:生成的别名和加载关联。
  • 也许有一对一关系的解决方案?

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

  • => 选择 posts . id AS t0_r0, posts . title AS t0_r1, posts . text AS t0_r2, posts . created_at AS t0_r3,posts . updated_at AS t0_r4,comments . id AS t1_r0, comments . title AS t1_r1, comments . text AS t1_r2,comments . post_id AS t1_r3,comments . created_at AS t1_r4,comments . updated_at AS t1_r5 来自 posts左外连接 comments开启 comments . post_id = posts . id

    最佳答案

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

  • :includes => 急切加载
  • :joins => 不急切加载

  • 所以如果你想直接加载评论,你必须使用包含,连接永远不会工作。

    接下来,由于 SQL 查询中使用了特定的 select 语法,所以预加载可以工作。换句话说,当与包含结合使用时,您指定的选择将被忽略,并且默认情况下将加载所有列。

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

    就我个人而言,我会使用您指定的第一个示例,但跳过选择并接受 comment.text 已加载的事实。比我能想到的任何其他场景都要好。

    关于ruby-on-rails - rails 事件记录选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4862804/

    相关文章:

    ruby-on-rails - 使用 rails.vim,为什么当事件缓冲区为空或不是 rails 项目的文件时命令不起作用?

    ruby-on-rails - 尽管已在该文件中定义,但 Rails 无法从文件中自动加载常量

    ruby-on-rails - 当用户记录不存在时,如何重定向到 404 页面?

    SQLITE:如果第一列为空,则选择另一列

    ruby-on-rails - Ruby on Rails 重复列名 : user_id: ALTER TABLE "articles" ADD "user_id" integer

    ruby-on-rails - Ruby on Rails - 类别为哈希或数据库表

    mysql - 让 ruby​​ activerecord 与 mysql 适配器一起工作

    php - Codeigniter 插入批处理不起作用

    php - 无法选择 * (ORA-00932 : inconsistent datatypes: expected CHAR got ADT)

    sql - 更新语句非常慢