Rails: select unique values from a column

I already have a working solution, but I would really like to know why this doesn't work:

ratings = Model.select(:rating).uniq
ratings.each { |r| puts r.rating }

It selects, but don't print unique values, it prints all values, including the duplicates. And it's in the documentation: http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields


Solution 1:

Model.select(:rating)

The result of this is a collection of Model objects. Not plain ratings. And from uniq's point of view, they are completely different. You can use this:

Model.select(:rating).map(&:rating).uniq

or this (most efficient):

Model.uniq.pluck(:rating)

Rails 5+

Model.distinct.pluck(:rating)

Update

Apparently, as of rails 5.0.0.1, it works only on "top level" queries, like above. Doesn't work on collection proxies ("has_many" relations, for example).

Address.distinct.pluck(:city) # => ['Moscow']
user.addresses.distinct.pluck(:city) # => ['Moscow', 'Moscow', 'Moscow']

In this case, deduplicate after the query

user.addresses.pluck(:city).uniq # => ['Moscow']

Solution 2:

If you're going to use Model.select, then you might as well just use DISTINCT, as it will return only the unique values. This is better because it means it returns less rows and should be slightly faster than returning a number of rows and then telling Rails to pick the unique values.

Model.select('DISTINCT rating')

Of course, this is provided your database understands the DISTINCT keyword, and most should.

Solution 3:

This works too.

Model.pluck("DISTINCT rating")

Solution 4:

If you want to also select extra fields:

Model.select('DISTINCT ON (models.ratings) models.ratings, models.id').map { |m| [m.id, m.ratings] }

Solution 5:

Model.uniq.pluck(:rating)

# SELECT DISTINCT "models"."rating" FROM "models"

This has the advantages of not using sql strings and not instantiating models