使用熟悉的Rails示例关联,其中帖子有很多评论:
控制器
...
@posts = Post.find(:all)
...
查看
...
<% @posts.comments.each do |comment| %>
...
评论关联在视图中加载延迟。我想确保在渲染视图之前,所有数据库查询都在控制器中进行。对于这个例子来说,这不是什么大问题,但它应该能够更容易地在一个更复杂的例子中发现SQL N + 1查询。
我想看到的控制器代码是:
...
@posts = Post.find(:all, :include => :comments)
...
一旦我们开始渲染视图,有没有办法阻止延迟加载关联?我希望有一种方法可以在关联缺失时引发异常,但仅限于一旦我们在视野中。
是否有任何插件可以执行此操作?
答案 0 :(得分:1)
这是一个几乎可以实现我想要的黑客:
内部config / initializers / prevent_lazy_loading_in_view.rb
class LazyLoadingPreventedInViewException < ActionView::TemplateError
def initialize template_error
super(template_error.instance_eval{@template}, template_error.instance_eval{@assigns}, template_error.original_exception)
end
end
class ActionController::Base
def render_with_lazy_load_prevention *args, &block
ActiveRecord::Base.connection.disconnect!
begin
render_without_lazy_load_prevention *args, &block
rescue ActionView::TemplateError => e
if e.message['not connected']
raise LazyLoadingPreventedInViewException.new(e)
else
raise e
end
end
ActiveRecord::Base.connection.reconnect!
end
alias_method_chain :render, :lazy_load_prevention
end
这将在渲染视图时断开数据库连接。任何延迟加载尝试都将导致包含“未连接”的消息的异常。我们拦截了这个异常并给它一个新名称“LazyLoadingPreventedInViewException”,只是为了让它稍微不那么神秘。
这绝对是 hack ,也不是很好。可能会给毫无防备的开发人员造成一些很大的困惑。如果我决定保留它,我当然不会继续生产。