This project is archived and is in readonly mode.
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>