Tag Archives: rails-performance

Faster and Lighter with pluck_to_hash Gem

Rails Active Record is very convenient. It has many utilities that makes dealing with data and persistence a breeze. Without AR, I don’t think I will stick with Rails.

However, as it goes, there’s no free lunch. Active Record objects are big and heavy. Often this is an acceptable trade off. However, when you need to process a lot of record and intend to just read the attributes values, AR might be too heavy and unnecessary.

When you only need values of some fields from a record, you can use AR’s `pluck`
For example you need the name and address of a user

User.where(id: 7).pluck(:name, :location).first
#
# ["John Shepard", "Normandy"]

This will retrieve the requested values without instantiating AR object, which save you both time and memory.

However, if you need to retrieve a lot of values from a collection of records, processing the arrays of values can become unwieldy. An example of this case is if you are building an “index” endpoint of an api with thousands of records per request. This is a real case that I have to do in one of my project.

For this, there is a handy gem that is called “pluck_to_hash”.
https://github.com/girishso/pluck_to_hash
No points for guessing it’s function. Basically it extends AR so you can do this:

User.limit(2).pluck_to_hash(:name, :location)
#
# [{:name=>"John Shepard", :location=>"Normandy"}, {:name=>"Urdnot Wrex", :location=>"Tuchanka"}]

Nice right?

Also, if you happens to use RABL for JSON templating, worry not, the gem also got you covered. RABL needs the record attributes to be accessible from a dot notation. This gem also supply `pluck_to_struct`, which looks like this

User.limit(2).pluck_to_struct(:name, :location)
#
# [#<struct name="John Shepard", location="Normandy"> #<struct name="Urdnot Wrex", location="Tuchanka">]

On one case, converting AR object to struct gave me ~3x faster response, while drastically reduce the memory usage. Unfortunately I don’t monitor exactly how much the memory saving from that particular endpoint, but the app server memory usage is reduced by 40%, so it should be more than that.

So, if you only need to read from some records and looking for more performance, this approach offer you some low hanging fruits.