# Ruby on Rails pluck method

ActiveRecord is an important part of Ruby on Rails ([the M in MVC](https://guides.rubyonrails.org/active_record_basics.html#what-is-active-record-questionmark)) 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](https://guides.rubyonrails.org/active_record_querying.html#pluck):

> [`pluck`](https://api.rubyonrails.org/v7.1.3.4/classes/ActiveRecord/Calculations.html#method-i-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.

```ruby
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.

```ruby
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.

```ruby
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.

```ruby
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](https://guides.rubyonrails.org/active_support_core_extensions.html#pluck) with the `pluck` method.

```ruby
[{ 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.

```ruby
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](https://github.com/rails/rails/pull/51565) was introduced by [fatkodima](https://github.com/fatkodima) and merged into Rails on April 13, 2024 to allow `ActiveRecord::Base#pluck` to accept hash values!

From the PR:

```ruby
# 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](https://guides.rubyonrails.org/active_record_querying.html#pluck)
    
2. [Rails API Docs - Active Record Calculations - pluck](https://api.rubyonrails.org/v7.1.3.4/classes/ActiveRecord/Calculations.html#method-i-pluck)
