Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I have ActiveRecord's pluck also return the column name for rendering in json?

def jsontest
   @users = User.all.limit(10)
   render json: @users
end

yields

{
...

"id": 7,
"name": "Sage Smith",
"email": "[email protected]",
"created_at": "2013-10-17T02:29:15.638Z",
"updated_at": "2013-10-17T02:29:15.638Z",
"password_digest": "$2a$10$taHk3udtWN61Il5I18akj.E90AB1TmdL1BkQBKPk/4eZ7YyizGOli",
"remember_token": "118f807d0773873fb5e4cd3b5d98048aef4f6f59",
"admin": false

...
}

But I would like to omit certain certain fields from this API, so I use pluck

def jsontest
  @users = User.all.limit(10).pluck(:id, :name, :email, :created_at) ###
  render json: @users
end

but pluck returns an array of only values, when I would like to have each object's attributes accessible by hash key.

[
...

    7,
    "Sage Smith",
    "[email protected]",
    "2013-10-17T02:29:15.638Z"

...    

]

So how can I effectively pluck the values and their keys?

I realize I could sweep through @users and grab the keys before plucking and recreate the hash, but I'm expecting there to be some convenience method that does exactly what I want.

like image 791
user Avatar asked Dec 27 '13 03:12

user


People also ask

What does pluck return in rails?

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.

What is pluck in Ruby?

ruby rails. Rails has a great, expressive term called pluck that allows you to grab a subset of data from a record. You can use this on ActiveRecord models to return one (or a few) columns. But you can also use the same method on regular old Enumerables to pull out all values that respond to a given key.


3 Answers

vee's answer is good, but I have one caveat. select instantiates a User for every row in the result, but pluck does not. That doesn't matter if you are only returning a few objects, but if you are returning large batches (50, 100, etc) you'll pay a significant performance penalty.

I ran into this problem, and I switched back to pluck:

#in user.rb
def self.pluck_to_hash(*keys)
  pluck(*keys).map{|pa| Hash[keys.zip(pa)]}
end

#in elsewhere.rb
User.limit(:10).pluck_to_hash(*%i[id name email created_at])

It's ugly, but it gets the hash you want, and fast.

I've updated it to reflect Mike Campbell's comment on Oct 11.

like image 148
Andrew Cone Avatar answered Oct 29 '22 14:10

Andrew Cone


Use select instead of pluck:

def jsontest
  @users = User.select('id, name, email, created_at').limit(10)
  render json: @users
end
like image 22
vee Avatar answered Oct 29 '22 15:10

vee


Created a simple pluck_to_hash gem to achieve this. https://github.com/girishso/pluck_to_hash

Usage example..

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

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

# Or use the shorter alias pluck_h

Post.limit(2).pluck_h(:id)
#
# [{:id=>213}, {:id=>214}]
#
like image 44
girishso Avatar answered Oct 29 '22 14:10

girishso