DreamWalker
DreamWalker

Reputation: 1387

Rails 4: select multiple attributes from a model instance

How do I fetch multiple attributes from a model instance, e.g.

Resource.first.attributes(:foo, :bar, :baz)
# or
Resource.where(foo: 1).fetch(:foo, :bar, :baz)

rather than returning all the attributes and selecting them manually.

Upvotes: 10

Views: 9851

Answers (3)

Joshua Pinter
Joshua Pinter

Reputation: 47471

To Fetch Multiple has_one or belongs_to Relationships, Not Just Static Attributes.

To fetch multiple relationships, such as has_one or belongs_to, you can use slice directly on the instance, use values to obtain just the values and then manipulate them with a map or collect.

For example, to get the category and author of a book, you could do something like this:

book.slice( :category, :author ).values 
#=> #<Category id: 1, name: "Science Fiction", ...>, #<Author id: 1, name: "Aldous Huxley", ...>

If you want to show the String values of these, you could use to_s, like:

book.slice( :category, :author ).values.map( &:to_s )
#=> [ "Science Fiction", "Aldous Huxley" ]

And you can further manipulate them using a join, like:

book.slice( :category, :author ).values.map( &:to_s ).join( "➝" )
#=> "Science Fiction ➝ Aldous Huxley"

Upvotes: 1

Dani
Dani

Reputation: 1022

How about pluck:

Resource.where(something: 1).pluck(:foo, :bar, :baz)

Which translates to the following SQL:

SELECT "resources"."foo", "resources"."bar" FROM, "resources"."baz" FROM "resources"

And returns an array of the specified column values for each of the records in the relation:

[["anc", 1, "M2JjZGY"], ["Idk", 2, "ZTc1NjY"]] 

http://guides.rubyonrails.org/active_record_querying.html#pluck

Couple of notes:

  • Multiple value pluck is supported starting from Rails 4, so if you're using Rails 3 it won't work.
  • pluck is defined on ActiveRelation, not on a single instnce.
  • If you want the result to be a hash of attribute name => value for each record you can zip the results by doing something like the following:

    attrs = [:foo, :bar, :baz]
    Resource.where(something: 1).pluck(*attrs).map{ |vals| attrs.zip(vals).to_h }
    

Upvotes: 6

Arup Rakshit
Arup Rakshit

Reputation: 118261

You will use the method slice.

Slice a hash to include only the given keys. Returns a hash containing the given keys.

Your code will be.

Resource.first.attributes.slice("foo", "bar", "baz")
# with .where
Resource.where(foo: 1).select("foo, bar, baz").map(&:attributes)

Upvotes: 20

Related Questions