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.
=> User.limit(10)
=> 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:
=> SELECT "first_name,last_name,email ..." FROM users LIMIT 10
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.
# config/application.rb
module MyApp
class Application < Rails::Application
config.active_record.enumerate_columns_in_select_statements = true
end
end
# User model specific
class User < ApplicationRecord
self.enumerate_columns_in_select_statements = true
end
When the setting value is set to true
the select statement will always
contains columns explicitly.
=> User.limit(10)
=> 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.