2012-08-06 125 views
1

在具有1-> N-> N关联的场景中。例如:发布 - >评论 - >投票(投票将是投票评论人的名单)。要显示一个网页,查询包括可能类似于:ActiveRecord - 查询执行后如何执行?

@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将被填充,每个评论将包括所有的投票。有没有办法做到这一点?

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

回答

2

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

尽管加载后期模型并稍后使用includes调用是不可能的。 includes通过对使用模型实例加载的关系使用join调用,以便每个关系只有一个数据库调用,而不是一个。

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

+0

我添加了一个编辑,在视图的查询工作只是一个例子。对于1-> N,也包括使用另一个选择。所以从技术上讲,可以向ActiveRecord添加一个函数来执行额外的选择并填充关联。不过谢谢你确认这件事尚不存在。 – mbdev 2012-08-06 18:24:10

0

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

# 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 %> 

不是最干净的方式,但它确实