I was looking into this today and it was a bit different–and much more complex–than what I expected, so I figured I’d pass on the results.~

On an association:

This gets a bit trickier when you add named scopes into the mix: the results change because named scope has taken over some of the methods. To understand this, you must remember that calling a named scope creates a new Scope object which wraps the upstream object. In addition to implementing the required querying magic, it provides a separate layer of caching entirely separate from the upstream object.

Keep in mind that both object associations and named scopes can only cache objects internally if they’re the same instance (i.e. saved to a variable), so two otherwise identical named scopes/association calls will only be cached at the query cache level (whether by Rails or the database). self often serves as this instance for an association when writing model code, but once you use a named scope, these are much more rarely cached, so count is often the best choice if a named scope is involved. Otherwise, size or length may be faster, depending on the scenario, but it still requires a full association load before it can cache the size. However, if you’re using counter_cache, you must use size to take advantage of them (unless you read the counter attribute directly).

Lastly, while count is a good choice, you shouldn’t get in a habit of using it on everything. Array#count was added in ruby 1.8.7 (and later). String#count exists, but it takes a parameter and returns the count of the number of occurrences of characters ('confused yet?'.count('ce') returns 3).