Ruby on Rails pluck method

Photo by Oleg Ivanov on Unsplash

Ruby on Rails pluck method

What is the pluck method and how to use it (with examples)

ActiveRecord is an important part of Ruby on Rails (the M in MVC) and is an Object Relational Mapping system (ORM) that maps the objects in your app to tables in your database. By using ActiveRecord (or any ORM) the attributes of your objects and the relationships between them can be saved and retrieved from your database without writing SQL statements. One of the helpful methods that ActiveRecord provides to help facilitate this is pluck.

What is the pluck method?

According to the Rails Guides:

pluck can be used to pick the value(s) from the named column(s) in the current relation. It accepts a list of column names as an argument and returns an array of values of the specified columns with the corresponding data type.

Put another way, pluck let's you specify one or more columns that are defined on an ActiveRecord model and returns the values in an Array.

Order.pluck(:id)
# SELECT orders.id FROM orders
=> [1, 2, 3]

Passing more than one column argument returns a nested array with values for each of the columns in each of the inner arrays. In this example the values for id and shipped will be in the inner arrays.

Order.pluck(:id, :status)
# SELECT orders.id, orders.status FROM orders
=> [[1, "shipped"], [2, "pending"], [3, "pending"]]

You can achieve similar results using select and map, but pluck allows you to just specify the column(s) you want and get that data back.

Order.select(:id).map{ |o| o.id }
Order.select(:id).map(&:id)
Order.select(:id, :status).map{ |o| [o.id, o.status] }

Using select and map together like this produces the same results, but you can replace the above code with pluck and avoid chaining multiple methods.

Plus, it's a little more concise, easier to read and usually faster.

What makes pluck faster than select and map?

When using select, it builds entire ActiveRecord objects from the database, which can be costly for large objects and for large queries if there are a lot of objects retrieved. Plus, there's the added step of mapping over the results to return the data in the shape that you want.

pluck, on the other hand, skips creating ActiveRecord objects entirely and only returns the data from the columns that you specified.

Using pluck to query multiple tables

You can also use pluck to query across joined tables as well.

Order.joins(:customer).pluck("orders.id, customers.first_name")

Using pluck on Enumerables

You can also use pluck on Enumerables to return the values you want by specifying the key(s). You just have to require ActiveSupport, which extends Enumerable with the pluck method.

[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
# => ["David", "Rafael", "Aaron"]
[{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
# => [[1, "David"], [2, "Rafael"]]

When to not use pluck

One thing to keep in mind when using pluck is if you already have access to an Array of ActiveRecord objects that you're retrieved from the database.

Calling pluck on that Array of ActiveRecord objects will trigger an additional query to the database. You can avoid this extra round trip to the database by using map instead.

order_ids = []
completed_orders = Order.where(status: "completed")
completed_orders.each do |order|  # .each will make a database call
    order_ids << order.id
end

# will trigger an unecessary database call
completed_orders.pluck(:total)

# the completed_orders array is already loaded in memory
# and we can just map over the array
completed_orders.map(&:total)

Recent Update to pluck

A Pull Request was introduced by fatkodima and merged into Rails on April 13, 2024 to allow ActiveRecord::Base#pluck to accept hash values!

From the PR:

# Before
Post.joins(:comments).pluck("posts.id", "comments.id", "comments.body")

# After
Post.joins(:comments).pluck(posts: [:id], comments: [:id, :body])

Resources

  1. RailsGuides: Finding by SQL - pluck

  2. Rails API Docs - Active Record Calculations - pluck