The regular AR pluck method returns the values only, for instance: Student.pluck(:firstname) => [“John”, “Mike”, “Simon”]
It’d be a nice feature to have a version which returns a hashes with the column names as keys: [{ firstname: “John”}, { firstname: “Mike” }, { firstname: “Simon” }]
I know this can (almost) be achieved with Student.select(:firstname).map(&:attributes) (it forces you to have an id attribute), but this involves instantiating lots of AR objects, which loses the benefit of pluck.
An example implementation would be:
def self.hash_pluck(*keys)
pluck(*keys).map{ |vals| Hash[keys.zip(Array(vals))] }
end
``
In some (probably bad) benchmarks I made comparing this to the select alternative, the select method was ~3.4x slower.
Benchmark.ips do |x|
x.report(“hash_pluck”) { Student.hash_pluck(:firstname) }
x.report(“select”) { Student.select(:firstname).map(&:attributes) }
x.compare!
end
The proposed method has more benefit when plucking multiple columns. Of course, you can still do pluck(:first, :last, :dob).map {|e| {first: e[0], last: e[1], dob: e[2]} }, but I guess that’s a little cumbersome and smelly. I’m not arguing the benefit – small benefit IMO – is worth the cost of adding and maintaining for years, but I do see its convenience.
I would definitely use this, given we don’t currently have many good options for querying against the database and getting non-ActiveRecord objects back.
I often want a fast way to serialize stuff as JSON (ie. without instantiating AR objects and then turning them back into hashes), and doing this using select_values is pretty cumbersome.
For example: render json: { tasks: current_user.tasks.hash_pluck(:id, :name, :completed) }
That said, I’d probably favour a more general way to query the database and get back arrays/hashes over something like hash_pluck, which would only handle very simple cases.