Ruby on Rails 4: Pluck results to hash

Viewed 28114

How can I turn:

Person.all.pluck(:id, :name)

to

[{id: 1, name: 'joe'}, {id: 2, name: 'martin'}]

without having to .map every value (since when I add or remove from the .pluck I have to do he same with the .map)

11 Answers

If you use postgresql, you can use json_build_object function in pluck method: https://www.postgresql.org/docs/9.5/functions-json.html

That way, you can let db create hashes.

Person.pluck("json_build_object('id', id, 'name', name)")
#=> [{id: 1, name: 'joe'}, {id: 2, name: 'martin'}]

There is pluck_all gem that do almost the same thing as pluck_to_hash do. And it claims that it's 30% faster. (see the benchmark here).

Usage:

Person.pluck_all(:id, :name)

If you have multiple attributes, you may do this for cleanliness:

Item.pluck(:id, :name, :description, :cost, :images).map do |item|
  {
    id:          item[0],
    name:        item[1],
    description: item[2],
    cost:        item[3],
    images:      item[4]
  }
end

The easiest way is to use the pluck method combined with the zip method.

attrs_array = %w(id name)
Person.all.pluck(attrs_array).map { |ele| attrs_array.zip(ele).to_h }

You can also create a helper method if you are using this method through out your application.

def pluck_to_hash(object, *attrs)
  object.pluck(*attrs).map { |ele| attrs.zip(ele).to_h }
end

Consider modifying by declaring self as the default receiver rather than passing Person.all as the object variable.

Read more about zip.

Here is a method that has worked well for me:

    def pluck_to_hash(enumerable, *field_names)
      enumerable.pluck(*field_names).map do |field_values|
        field_names.zip(field_values).each_with_object({}) do |(key, value), result_hash|
          result_hash[key] = value
        end
      end
    end

I know it's an old thread but in case someone is looking for simpler version of this

Hash[Person.all(:id, :name)]

Tested in Rails 5.

Related