Rails pluck to hash


2018-05-10 · 2 min read

In Rails, pluck is a shortcut to select one or more attributes without loading the corresponding records just to filter out the selected attributes. It returns an Array of attribute values.

Person.pluck(:name)
# SELECT people.name FROM people
# => ["Zosia", "Basia", "Jurek"]

This is similar to the following, but pluck is much more performant

Person.all.map { |p| p.slice(:id, :name) }

There is also select in ActiveRecord. It modifies the SQL SELECT statement for the query so that only certain fields are retrieved. It doesn't return an array, but a relation object. Thus, it's usually less performant than pluck as it needs to instatiante those object.

Person.select(:id,:name)

.select adds id into the hash even if it is not requested. This method creates k Person objects after the SQL query result and then iterates them to return the JSON.

pluck can be combined with map to create a hash between selected fields and their values:

Person.all.pluck(:id, :name).map { |id, name| { id: id, name: name } }

This method is more efficient than select. pluck only returns the selected columns whereas the other solution returns all columns. Also, it does not instantiate Person objects nor need to assign attributes to the models.

It is possible to make pluck+map method simpler by using spread operator along with zip function

attrs = %w(id name)
Person.pluck(*attrs).map { |p| attrs.zip(p).to_h }

Alternatively, as_json may be used to specify a subset of fields

Person.all.as_json(only: [:id, :name])

Finally, there is pluck_to_hash which extends ActiveRecord pluck to return array of hashes. It also supports Struct via pluck_to_struct method.

Post.limit(2).pluck_to_hash(:id, :title)
# => [{:id=>213, :title=>"foo"}, {:id=>214, :title=>"bar"}]

It also allows to alias fields

User.pluck_to_hash(:id, 'created_at::date as custom_date', 'created_at::time as custom_time')
# => [{:id=>23, :custom_date=>Fri, 11 Jul 2014, :custom_time=>2000-01-01 07:54:36 UTC}]

In some contrived examples, pluck_to_hash is around 4x faster than using ActiveRecord's select and arount 8x faster than as_json method. This may be a good indication of improved performance in real world scenerios.