Michael Anhari

Returning an empty result set from ActiveRecord that doesn't break method chaining

A top down view of an empty tea cup with a spoon inside of it.

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

Newsletter

I'm working on sending out a weekly newsletter. I'll make it as easy as possible to unsubscribe at any time.