Hieu Nguyen

TIL - Weird behavior of pluck and uniq in ActiveRecord

Aug 7 2018


Normally, when fetching raw columns data from database in ActiveRecord, pluck is prefered to map because it only fetches the necessary columns and does not create any ActiveRecord objects:

# fetch all columns and create activerecord objects
Product.all.map(&:name)

# fetch only necessary columns and create activerecord objects
Product.select(:name).map(&:name)

# fetch only necessary columns and create only necessary primitive objects
Product.pluck(:name)

However, when using with uniq and non-top-level scope, it can catch us offguard:

Product.uniq.pluck(:name) # works, only unique names are returned

category.products.uniq.pluck(:name) # does not work, all names are returned

In that case, we can use uniq after the pluck, but it may cost us a lot of memory to handle all the returned data:

category.products.pluck(:name).uniq # works, but waste a lot of memory to store redundant data

A faster solution is using DISTINCT keyword directly in pluck, but it may harm readability/maintainability:

category.products.pluck('DISTICT name') # works, but may fail if name is an aliased column

I wonder why there is this weird behavior…