better_pluck
Main purpose is to reduce loading into memory expensive ActiveRecord objects, where it is not needed (for read-only operations).
better_pluck adds struct_pluck, struct_pluck_with_display_name to ActiveRecord. These methods allow you to pluck not only database columns but also virtual methods and association data, returning lightweight Struct objects instead of heavy ActiveRecord instances.
This approach can reduce memory usage by up to 3-20x compared to loading full ActiveRecord objects.
Primary purpose: to be used in huge form dropdowns for select inputs.
Installation
Add this line to your application's Gemfile:
gem 'better_pluck'
Usage
Basic usage
You can pluck database columns and instance methods:
# Assuming Article has a method :name_on_site
articles = Article.struct_pluck(:id, :name, :email, :name_on_site)
articles.first.id # => 1
articles.first.name_on_site # => "My Article" (virtual method)
Associations
You can also pluck data from nested associations:
articles = Article.struct_pluck(
:id,
:name,
author: [:name, :email, :display_name]
)
articles.first..email # => "author@example.com"
articles.first..display_name # => "John Doe"
Pluck with Display Name
A convenience method specifically for dropdown lists and collections:
# Automatically includes :display_name for the model and associations
articles = Article.struct_pluck_with_display_name(:id, :name, author: [:name, :email])
articles.first.display_name # => "Article Name"
articles.first..display_name # => "Author Name <author@example.com>"
select_with_joins method
You can use the select_with_joins method which will create field aliases for associations instead of fully fetching activerecord objects for them. The main model can be selected with specific columns or fully fetched. Main model is kept as ActiveRecord object.
# Example with positional arguments for base model
users = User.select_with_joins(:id, :name, organization: :name)
# SELECT users.id, users.name, organizations.name AS organization_name FROM users LEFT JOIN organizations ...
users.first.name # => "John"
users.first.organization_name # => "Acme Corp"
# Example fetching all base model columns
articles = Article.select_with_joins(author: [:name])
# SELECT articles.*, authors.name AS author_name FROM articles LEFT JOIN authors ...
articles.first. # => "John Doe"