在具有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。我知道视图不是运行查询的最佳位置,这只是一个例子。
答案 0 :(得分:2)
在最新版本的rails中,所有finder-methods都会返回一个代理对象,只有在你发送一些迭代器方法(如all
或first
时才会触发数据库调用。这就是为什么你可以链接所有调用,如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 %>
不是最干净的方式,但它完成了工作