Ruby Rails Quick Tips - ActiveRecord::Calculations.pluck

Pluck is an ActiveRecord calculation method introduced in Nov 2011 and is designed to return a collection of values by performing a single column SELECT query as direct SQL .

Now what problem could this help solve and how does it affect us?

How often have you run into some code similar to this?

users = User . all => [ #<User id: 1, email: 'dude@example.com', active: true>, #<User id: 2, email: 'sweet@example.com', active: false>] users . map ( & :email ) => [ 'dude@example.com' , 'sweet@example.com' ] # I've separated the AR result from the ruby #map for clarity # this would normally be called as User.all.map(&:email)

What is happening here?

We are returning all records of the User ActiveRecord object and asking for a new collection containing each email . It definitely gets the job done... do we really need to fix this? Possibly. That decision will definitely be up to the person implemented but let's explore a different way to get the same result in a more efficient and performant way.

ActiveRecord's .select will return AR records as the result, but will only return with the explicitly requested attributes. The User class is still being instantiated for each result. Depending on your memory constraints this may not be a problem, but nevertheless it's using up memory that just didn't need to be used.

emails = User . select ( :email ) => [ #<User email: 'dude@example.com'>, #<User email: 'sweet@example.com'>] emails . map ( & :email ) => [ 'dude@example.com' , 'sweet@example.com' ]

We're getting closer. At least we are now only pulling back the data we care about. This is only marginally better than our first attempt and it feels weird. We've asked to only select a particular attribute and then we have to ask for it to be the only thing in a collection.

Lets try one more time using the pluck method.

User . pluck ( :email ) => [ 'dude@example.com' , 'sweet@example.com' ]

Whoa! Well that's a bit different. Definitely less code but what is it doing? .pluck is a (misplaced?) calculation method that, like described above, is returning an array of results based on the database column that was requested. Where the previous example returned full AR User records and then performed the map , this example went directly to the database with a SQL call and returned only the result needed. In many cases this is far cleaner and definitely more efficient.

In addition, other relation methods can be chained together and affect the end result query that is generated.

User . where ( active :true ). pluck ( :email )

SELECT email FROM 'users' WHERE 'users' . 'active' = 't'