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.