Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Chaining named scopes executes an unnecessary query.

#6543

I found a rather serious problem with named scopes in ActiveRecord 2.3.X. After analyzing my logs I noticed that chaining named scopes actually executes extra unscoped queries along the way. Which is a big deal, especially if they are loading thousands of records.

The fix is actually very easy, but it involved removing code, and I have no idea what the purpose of the code is. Take the original method:

def named_scope(name, options = {}, &block)

name = name.to_sym

scopes[name] = lambda do |parent_scope, *args|
  Scope.new(parent_scope, case options
    when Hash
      options
    when Proc
      if self.model_name != parent_scope.model_name
        options.bind(parent_scope).call(*args)
      else
        options.call(*args)
      end
  end, &block)
end

singleton_class.send :define_method, name do |*args|
  scopes[name].call(self, *args)
end

end

Notice this line:

if self.model_name != parent_scope.model_name

The "parent_scope.model_name" actually executes a query, because parent scope can be a proxy that delegates its method calls off to the query result. So doing something like:

user = User.first user.orders.state_equals("pending").total_greater_than(100).count

The last line should execute a single "count" query. Instead, because of line mentioned above, it actually executes a "select all" for the users orders with state "pending". Then it executes the count query.

The fix ix very easy. Change this:

if self.model_name != parent_scope.model_name

options.bind(parent_scope).call(*args)

else

options.call(*args)

end

To this:

if self.model_name != parent_scope.model_name

options.bind(parent_scope).call(*args)

else

options.call(*args)

end

Again, I have no idea what the line in question does. Hence the reason I didn't create a pull request on github.

Reported by Ben Johnson · March 8th, 2011 @ 03:47 AM

State: new
Milestone: none
Assigned to: nobody
Importance: none

Activity

No comments yet.