1

在具有 1->N->N 关联的场景中。例如:帖子->评论->投票(投票将是对评论投票的人的姓名列表)。要显示包含查询的页面,可能如下所示:

@post = Post.where(:id => 100).includes({:comments => :votes}).first

我开始添加缓存支持。这意味着如果评论部分已经被缓存,我将不需要一直运行包含评论/投票。所以我想知道是否有办法让代码看起来像:

# controller
@post = Post.find(100)

# view
<% cache('comments', @post.last_comment_time do %>
    <% @post.includes({:comments => :votes}).comments.each do |comment| # ???? %>
<% end %>

运行“后查询”包括,将“填写”关联。因此@post.comments 将被填充,并且每条评论都将包含所有投票。有没有办法做到这一点?

PS 我知道视图不是运行查询的最佳位置,这只是一个示例。

4

2 回答 2

2

all在最新版本的 rails 中,所有 finder-methods 都返回一个代理对象,只有在您向它发送一些迭代器方法(如或first在您的情况下)时才会触发数据库调用。这就是为什么您可以链接所有调用,例如Post.where.order.sort.bla.

includes虽然加载后模型并稍后使用调用是不可能的。includes通过join调用与模型实例一起加载的关系来工作,这样您就只有一个数据库调用,而不是每个关系一个。

在您的视图中执行 active_record 代码也是一种不好的做法。数据检索是控制器的责任,而不是视图。

于 2012-08-06T17:31:35.737 回答
1

这是一个相当古老的问题,但现在可以像这样完成

# controller
@post = Post.find(100)

# view
<% cache('comments', @post.last_comment_time do %>
    <% ActiveRecord::Associations::Preloader.new.preload @post, comments: :votes # this will trigger one query %>
    <% @post.comments.each do |comment| # this will not trigger any additional queries %>
<% end %>

不是最干净的方式,但它可以完成工作

于 2015-11-20T18:47:42.180 回答