开发者

Raise exception when associations are lazy-loaded in the view

Using a familiar Rails example association where Posts have many Comments:

Controller

...
@posts = Post.find(:all)
...

View

...
<% @posts.comments.each do |comment| %>
...

The comments association gets lazy-loaded while in the view. I would like to ensure that all database queries happen in the controller before we get to rendering the view. It's n开发者_StackOverflowot a big deal for this example, but it should make it easier to spot SQL N+1 queries in a more complicated example.

The controller code I would like to see is this:

...
@posts = Post.find(:all, :include => :comments)
...

Is there a way to prevent lazy-loading associations once we start rendering the view? I'm hoping there is a way to cause it to throw an exception when an association is missing, but only once we're in the view.

Are there any plug-ins that do this?


This is a hack that almost does what I want:

Inside 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

This will disconnect the database while rendering the view. Any lazy-load attempts will cause an exception with message containing "not connected". We intercept this exception and give it a new name "LazyLoadingPreventedInViewException" just to make it slightly less cryptic.

This is definitely a hack, and not very good one either. Could cause some great confusion for the unsuspecting developer. If I decide to keep it, I certainly wont keep it on in production.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜