Rails 7.1 allows ActiveRecord reselect to accept a hash

railsDecember 19, 2023Dotby Alkesh Ghorpade

Rails 7.1 allowed ActiveRecord::QueryMethods#select to receive hash values. The reselect method needed this functionality added. Within the same Rails 7.1 release, the Rails team adds the ability to pass a hash to the ActiveRecord#reselect method.

Before Rails 7.1

ActiveRecord#reselect method

The reselect method in ActiveRecord is a powerful tool for fine-tuning the columns retrieved from your database queries. Think of it as adding a layer of precision to your existing query, allowing you to focus on the specific data you need.

reselect accepts various arguments, with the most common being:

  • Symbols: Specify the columns you want to select.

  • Strings: Provide raw SQL expressions for custom selection.

# select 'id' and 'name' from 'users' table
users = User.all.reselect(:id, :name)

# select 'created_at' with alias 'date_joined'
users = users.reselect(created_at: :date_joined)

# remove 'email' from the selection
users = users.reselect(:id, :name).except(:email)

As seen in the above example, you can update what columns are retrieved after choosing specific ones with ActiveRecord's reselect.

When working with joins, you need to pass raw SQL strings as shown below:

posts = Post
          .joins(:author)
          .select('posts.title', 'authors.name')

posts = posts
          .reselect(
            'posts.title', 
            'authors.name', 
          )

# Now posts will have all three columns for each record

If you try to pass a hash to the reselect method, it fails to execute and raises an Unsupported argument type: Hash error.

posts = posts
          .reselect(
            :title,
            authors: [:name]
          )

An error occurred when inspecting the object: #<Arel::Visitors::UnsupportedVisitError: Unsupported argument type: Hash. Construct an Arel node instead.>
...

In Rails 7.1

Rails 7.1 allows the ActiveRecord reselect method to accept the hash of columns and aliases. Passing the hash to the reselect method executes the query successfully without raising any error.

The benefits of using a hash in the reselect method are:

  • Enhanced Readability: Your code becomes cleaner and more expressive, revealing the exact data you target for the primary model and its associations.

  • Greater Flexibility: Easily adjust the selected columns and aliases for the primary model and its associations without rewriting the entire query.

Here's how you can define selections for associations:

Symbol Shortcuts

For more straightforward associations, you can automatically use specific symbols to include commonly desired columns for the associated model.

posts = Post.all.reselect(
  id: :post_id,
  title: :post_title,
  authors: [:name]
)

Nested Hashes

Use nested hashes to represent each associated model and its desired columns.

posts = Post.all.reselect(
  id: :post_id,
  title: :post_title,
  authors: {
    name: :author_name,
  }
)

To know more about this feature, please refer to this PR.

Closing Remark

Could your team use some help with topics like this and others covered by ShakaCode's blog and open source? We specialize in optimizing Rails applications, especially those with advanced JavaScript frontends, like React. We can also help you optimize your CI processes with lower costs and faster, more reliable tests. Scraping web data and lowering infrastructure costs are two other areas of specialization. Feel free to reach out to ShakaCode's CEO, Justin Gordon, at justin@shakacode.com or schedule an appointment to discuss how ShakaCode can help your project!
Are you looking for a software development partner who can
develop modern, high-performance web apps and sites?
See what we've doneArrow right