Rails 7 adds setting for enumerating columns in select statements

Ashik Salman

Ashik Salman

October 13, 2021

This blog is part of our  Rails 7 series.

Rails 7 has introduced a new setting called enumerate_columns_in_select_statements for enumerating columns in activerecord select query statements by which we can avoid common ActiveRecord::PreparedStatementCacheExpired errors.

Rails uses prepared statements for database query efficiency. When prepared statements are being used, the repeated queries will be cached based on the prepared statement query plan at Postgres database level. This cached value will become invalid when the returned results are changed.

Whenever we make any schema changes to database tables while application is running, the cached select statements with wildcard column definition will raise PreparedStatementCacheExpired error since the query output has modified.

Before

1=> User.limit(10)
2=> SELECT * FROM users LIMIT 10

If we use the select query with *, then any change in the database schema for the particular table (eg: users) will invalidate the prepared statement cache and result in the PreparedStatementCacheExpired error. The solution here is to mention the columns explicitly in the select statement as shown below:

1=> SELECT "first_name,last_name,email ..." FROM users LIMIT 10

Rails 7 onwards

Rails 7 adds a new setting, by which we can ensure all select statements are generated by enumerating the columns explicitly. Hence any modifications to the database schema won't result in PreparedStatementCacheExpired, instead the prepared statements will be changed and the respective query will be cached freshly by the Postgres database.

We can either configure the setting for all models or at specific model level.

1# config/application.rb
2module MyApp
3  class Application < Rails::Application
4    config.active_record.enumerate_columns_in_select_statements = true
5  end
6end
7
8# User model specific
9class User < ApplicationRecord
10  self.enumerate_columns_in_select_statements = true
11end

When the setting value is set to true the select statement will always contains columns explicitly.

1=> User.limit(10)
2=> SELECT "first_name,last_name,email ..." FROM users LIMIT 10

Check out this pull request for more details.

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.