ActiveRecord - 执行查询后如何做?

时间:2012-08-06 17:03:54

标签: ruby-on-rails activerecord

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

@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-query”包括,将“填写”关联。所以@ post.comments将被填充,每个评论将包括所有投票。有没有办法实现这个目标?

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

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分: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 %>

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