Returning an empty result set from ActiveRecord that doesn't break method chaining
Occassionally in Rails, you'll want to conditionally return an empty result set from a query. You might write something like this:
@photos = if some_condition?
Photo.all
else
[]
end
If some_condition?
is met we return all of the photos from our database, otherwise we return an empty array.
The shortcomings of this approach
The issue with returning an empty array becomes evident if you try to chain ActiveRecord
methods off of this object later on.
@photos.order(created_at: :desc)
# => NoMethodError: undefined method `order' for []:Array
Since []
isn't an ActiveRecord
relation, your code blows up 💥.
ActiveRecord's null object implementation
Luckily enough, ActiveRecord
added a none
method sometime in Rails 4 to help us out.
From the Rails documenation, this is described as the following:
The returned relation implements the Null Object pattern. It is an object with defined null behavior and always returns an empty array of records without querying the database.
Any subsequent condition chained to the returned relation will continue generating an empty relation and will not fire any query to the database.
Used in cases where a method or scope could return zero records but the result needs to be chainable.
We can leverage .none
to keep the chainability (new word?) of our @photos
object.
@photos = if some_condition?
Photo.all
else
Photo.none
end
@photos.order(created_at: :desc) # all good