user
user

Reputation: 3456

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.

Upvotes: 34

Views: 23697

Answers (7)

khiav reoy
khiav reoy

Reputation: 1403

@girishso's gem is great, but my project is in Rails 3. It doesn't work.

This article is helpful to me, or install pluck_all gem to achieve this.

Usage:

User.limit(10).pluck_all(:id, :name, :email, :created_at)

Upvotes: 0

Diogenes Creosote
Diogenes Creosote

Reputation: 1942

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.

Upvotes: 52

anonn023432
anonn023432

Reputation: 3120

You can pull the data along with the column name as:

@users = User.all.limit(10)
                 .pluck(:id, :name, :email, :created_at)
                 .map {|id, name, email, created_at| { id: id, name: name, 
                                                       email: email, 
                                                       created_at: created_at } }

This will pull the data and map it according to how you want it. One advantage of using pluck over select is that you can use joins along with it.

Upvotes: 1

Alex Kojin
Alex Kojin

Reputation: 5204

Fastest way to return hash of users with selected columns is use ActiveRecord::Base.connection.select_all method.

sql = User.select('id, name, email, created_at').limit(10).to_sql
@users = ActiveRecord::Base.connection.select_all(sql)
render json: @users

Upvotes: 6

Zvi
Zvi

Reputation: 617

@andrewCone - It should be like this:

User.limit(:10).pluck_to_hash([:id, :name, :email, :created_at])

Upvotes: 0

girishso
girishso

Reputation: 369

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}]
#

Upvotes: 14

vee
vee

Reputation: 38645

Use select instead of pluck:

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

Upvotes: 23

Related Questions