This project is archived and is in readonly mode.

#6543 new
Ben Johnson

Chaining named scopes executes an unnecessary query.

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

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.

No comments found

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

People watching this ticket

Pages