23 October 2014
The Big Difference Between Empty And None
Given an ActiveRecord class with a
class User < ActiveRecord::Base has_many :records ... end
…this is a mistake:
user = User.first user.records.none?
Why, you ask?
Let’s step back for a second. At the database level, the correct way to answer the
question, “Are there any records that belong to this user?” is to
fire off a SQL statement with a
SELECT count(*) clause, and see whether the result is
greater than 0. That’s what we want to have happen behind the scenes.
However, that’s not what’s happening when we call
none? is not defined on
fancy/magical Rails class that is responsible for abstracting away cross-table SQL queries), but rather, it is
defined on the plain old Ruby module
So, what you might assume (as I did) is doing something smart and reasonable (i.e. performing a SQL count, and comparing the result with zero), is actually doing something VERY stupid (i.e. loading a ton of Ruby objects into memory and performing a count on them there). You can imagine that if users had thousands of records each, this line could constitute a serious drain on your application’s resources.
The method you were probably reaching for was
performs a SQL
count(). For reference, here’s a breakdown of some other
count-related methods on
Enumerable and their
|Question||Enumberable Method||ActiveRecord::Relation Method|
|More than zero objects in collection?||
|Zero objects in collection?||
|More than one object in collection?||
|Exactly one object the collection?||