Fix
eager_loadwhen loadinghas_manyassocations with composite primary keys.This would result in some records being loaded multiple times.
Martin-Alexander
Rails 8.0.4 (October 28, 2025)
Fix SQLite3 data loss during table alterations with CASCADE foreign keys.
When altering a table in SQLite3 that is referenced by child tables with
ON DELETE CASCADEforeign keys, ActiveRecord would silently delete all data from the child tables. This occurred because SQLite requires table recreation for schema changes, and during this process the original table is temporarily dropped, triggering CASCADE deletes on child tables.The root cause was incorrect ordering of operations. The original code wrapped
disable_referential_integrityinside a transaction, butPRAGMA foreign_keyscannot be modified inside a transaction in SQLite - attempting to do so simply has no effect. This meant foreign keys remained enabled during table recreation, causing CASCADE deletes to fire.The fix reverses the order to follow the official SQLite 12-step ALTER TABLE procedure:
disable_referential_integritynow wraps the transaction instead of being wrapped by it. This ensures foreign keys are properly disabled before the transaction starts and re-enabled after it commits, preventing CASCADE deletes while maintaining data integrity through atomic transactions.Ruy Rocha
Add support for bound SQL literals in CTEs.
Nicolas Bachschmidt
Fix
belongs_toassociations not to clear the entire composite primary key.When clearing a
belongs_toassociation that references a model with composite primary key, only the optional part of the key should be cleared.zzak
Fix invalid records being autosaved when distantly associated records are marked for deletion.
Ian Terrell, axlekb AB
Rails 8.0.3 (September 22, 2025)
Fix query cache for pinned connections in multi threaded transactional tests
When a pinned connection is used across separate threads, they now use a separate cache store for each thread.
This improve accuracy of system tests, and any test using multiple threads.
Heinrich Lee Yu, Jean Boussier
Don't add
id_valueattribute alias when attribute/column with that name already exists.Rob Lewis
Fix false positive change detection involving STI and polymorphic has one relationships.
Polymorphic
has_onerelationships would always be considered changed when defined in a STI child class, causing nedless extra autosaves.David Fritsch
Skip calling
PG::Connection#cancelincancel_any_running_querywhen using libpq >= 18 with pg < 1.6.0, due to incompatibility. Rollback still runs, but may take longer.Yasuo Honda, Lars Kanis
Fix stale association detection for polymorphic
belongs_to.Florent Beaurain, Thomas Crambert
Fix removal of PostgreSQL version comments in
structure.sqlfor latest PostgreSQL versions which include\restrictBrendan Weibrecht
Allow setting
schema_formatin database configuration.primary: schema_format: rubyUseful in multi-database setups to have different formats per-database.
T S Vallender
Use ntuples to populate row_count instead of count for Postgres
Jonathan Calvert
Fix
#mergewith#oror#andand a mixture of attributes and SQL strings resulting in an incorrect query.base = Comment.joins(:post).where(user_id: 1).where("recent = 1") puts base.merge(base.where(draft: true).or(Post.where(archived: true))).to_sqlBefore:
SELECT "comments".* FROM "comments" INNER JOIN "posts" ON "posts"."id" = "comments"."post_id" WHERE (recent = 1) AND ( "comments"."user_id" = 1 AND (recent = 1) AND "comments"."draft" = 1 OR "posts"."archived" = 1 )After:
SELECT "comments".* FROM "comments" INNER JOIN "posts" ON "posts"."id" = "comments"."post_id" WHERE "comments"."user_id" = 1 AND (recent = 1) AND ( "comments"."user_id" = 1 AND (recent = 1) AND "comments"."draft" = 1 OR "posts"."archived" = 1 )Joshua Young
Fix inline
has_and_belongs_to_manyfixtures for tables with composite primary keys.fatkodima
Fix migration log message for down operations.
Bernardo Barreto
Prepend
extra_flagsin postgres'structure_loadWhen specifying
structure_load_flagswith a postgres adapter, the flags were appended to the default flags, instead of prepended. This caused issues with flags not being taken into account by postgres.Alice Loeser
Fix
annotatecomments to propagate toupdate_all/delete_all.fatkodima
Fix checking whether an unpersisted record is
include?d in a strictly loadedhas_and_belongs_to_manyassociation.Hartley McGuire
create_or_find_bywill now correctly rollback a transaction.When using
create_or_find_by, raising a ActiveRecord::Rollback error in aafter_savecallback had no effect, the transaction was committed and a record created.Edouard Chin
Gracefully handle
Timeout.timeoutfiring during connection configuration.Use of
Timeout.timeoutcould result in improperly initialized database connection.This could lead to a partially configured connection being used, resulting in various exceptions, the most common being with the PostgreSQLAdapter raising
undefined method 'key?' for nilorTypeError: wrong argument type nil (expected PG::TypeMap).Jean Boussier
Fix stale state for composite foreign keys in belongs_to associations.
Varun Sharma
Rails 8.0.2.1 (August 13, 2025)
Call inspect on ids in RecordNotFound error
[CVE-2025-55193]
Gannon McGibbon, John Hawthorn
Rails 8.0.2 (March 12, 2025)
Fix inverting
rename_enum_valuewhen:from/:toare provided.fatkodima
Prevent persisting invalid record.
Edouard Chin
Fix inverting
drop_tablewithout options.fatkodima
Fix count with group by qualified name on loaded relation.
Ryuta Kamizono
Fix
sumwith qualified name on loaded relation.Chris Gunther
The SQLite3 adapter quotes non-finite
Numericvalues like "Infinity" and "NaN".Mike Dalessio
Handle libpq returning a database version of 0 on no/bad connection in
PostgreSQLAdapter.Before, this version would be cached and an error would be raised during connection configuration when comparing it with the minimum required version for the adapter. This meant that the connection could never be successfully configured on subsequent reconnection attempts.
Now, this is treated as a connection failure consistent with libpq, raising a
::ActiveRecord::ConnectionFailedand ensuring the version isn't cached, which allows the version to be retrieved on the next connection attempt.Joshua Young, Rian McGuire
Fix error handling during connection configuration.
Active Record wasn't properly handling errors during the connection configuration phase. This could lead to a partially configured connection being used, resulting in various exceptions, the most common being with the PostgreSQLAdapter raising
undefined methodkey?' for nilorTypeError: wrong argument type nil (expected PG::TypeMap)`.Jean Boussier
Fix a case where a non-retryable query could be marked retryable.
Hartley McGuire
Handle circular references when autosaving associations.
zzak
PoolConfig no longer keeps a reference to the connection class.
Keeping a reference to the class caused subtle issues when combined with reloading in development. Fixes #54343.
Mike Dalessio
Fix SQL notifications sometimes not sent when using async queries.
Post.async_count ActiveSupport::Notifications.subscribed(->(*) { "Will never reach here" }) do Post.count endIn rare circumstances and under the right race condition, Active Support notifications would no longer be dispatched after using an asynchronous query. This is now fixed.
Edouard Chin
Fix support for PostgreSQL enum types with commas in their name.
Arthur Hess
Fix inserts on MySQL with no RETURNING support for a table with multiple auto populated columns.
Nikita Vasilevsky
Fix joining on a scoped association with string joins and bind parameters.
class Instructor < ActiveRecord::Base has_many :instructor_roles, -> { active } end class InstructorRole < ActiveRecord::Base scope :active, -> { joins("JOIN students ON instructor_roles.student_id = students.id") .where(students { status: 1 }) } end Instructor.joins(:instructor_roles).firstThe above example would result in
::ActiveRecord::StatementInvalidbecause theactivescope bind parameters would be lost.Jean Boussier
Fix a potential race condition with system tests and transactional fixtures.
Sjoerd Lagarde
Fix autosave associations to no longer validated unmodified associated records.
Active Record was incorrectly performing validation on associated record that weren't created nor modified as part of the transaction:
Post.create!(author: User.find(1)) # Fail if user is invalidJean Boussier
Remember when a database connection has recently been verified (for two seconds, by default), to avoid repeated reverifications during a single request.
This should recreate a similar rate of verification as in Rails 7.1, where connections are leased for the duration of a request, and thus only verified once.
Matthew Draper
Rails 8.0.1 (December 13, 2024)
Fix removing foreign keys with
:restrictaction for MySQL.fatkodima
Fix a race condition in
ActiveRecord::Base#method_missingwhen lazily defining attributes.If multiple thread were concurrently triggering attribute definition on the same model, it could result in a
NoMethodErrorbeing raised.Jean Boussier
Fix MySQL default functions getting dropped when changing a column's nullability.
Bastian Bartmann
Fix
add_unique_constraint/add_check_constraint/add_foreign_keyto be revertible when given invalid options.fatkodima
Fix asynchronous destroying of polymorphic
belongs_toassociations.fatkodima
Fix
insert_allto not update existing records.fatkodima
NOT VALIDconstraints should not dump increate_table.Ryuta Kamizono
Fix finding by nil composite primary key association.
fatkodima
Properly reset composite primary key configuration when setting a primary key.
fatkodima
Fix Mysql2Adapter support for prepared statements
Using prepared statements with MySQL could result in a
NoMethodErrorexception.Jean Boussier, Leo Arnold, zzak
Fix parsing of SQLite foreign key names when they contain non-ASCII characters
Zacharias Knudsen
Fix parsing of MySQL 8.0.16+ CHECK constraints when they contain new lines.
Steve Hill
Ensure normalized attribute queries use
IS NULLconsistently forniland normalizednilvalues.Joshua Young
Fix
sumwhen performing a grouped calculation.User.group(:friendly).sumno longer worked. This is fixed.Edouard Chin
Restore back the ability to pass only database name to
DATABASE_URL.fatkodima
Rails 8.0.0.1 (December 10, 2024)
- No changes.
Rails 8.0.0 (November 07, 2024)
Fix support for
query_cache: falseindatabase.yml.query_cache: falsewould no longer entirely disable the Active Record query cache.zzak
Rails 8.0.0.rc2 (October 30, 2024)
NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
Ryuta Kamizono
The
db:preparetask no longer loads seeds when a non-primary database is created.Previously, the
db:preparetask would load seeds whenever a new database is created, leading to potential loss of data if a database is added to an existing environment.Introduces a new database config property
seedsto control whether seeds are loaded duringdb:preparewhich defaults totruefor primary database configs andfalseotherwise.Fixes #53348.
Mike Dalessio
PG::UnableToSend: no connection to the serveris now retryable as a connection-related exceptionKazuma Watanabe
Fix strict loading propagation even if statement cache is not used.
Ryuta Kamizono
Allow
rename_enumaccepts two from/to name arguments asrename_tabledoes so.Ryuta Kamizono
Rails 8.0.0.rc1 (October 19, 2024)
Remove deprecated support to setting
ENV["SCHEMA_CACHE"].Rafael Mendonça França
Remove deprecated support to passing a database name to
cache_dump_filename.Rafael Mendonça França
Remove deprecated
ActiveRecord::ConnectionAdapters::ConnectionPool#connection.Rafael Mendonça França
Remove deprecated
config.active_record.sqlite3_deprecated_warning.Rafael Mendonça França
Remove deprecated
config.active_record.warn_on_records_fetched_greater_than.Rafael Mendonça França
Remove deprecated support for defining
enumwith keyword arguments.Rafael Mendonça França
Remove deprecated support to finding database adapters that aren't registered to Active Record.
Rafael Mendonça França
Remove deprecated
config.active_record.allow_deprecated_singular_associations_name.Rafael Mendonça França
Remove deprecated
config.active_record.commit_transaction_on_non_local_return.Rafael Mendonça França
Fix incorrect SQL query when passing an empty hash to
ActiveRecord::Base.insert.David Stosik
Allow to save records with polymorphic join tables that have
inverse_ofspecified.Markus Doits
Fix association scopes applying on the incorrect join when using a polymorphic
has_many through:.Joshua Young
Allow
ActiveRecord::Base#pluckto accept hash arguments with symbol and string values.Post.joins(:comments).pluck(:id, comments: :id) Post.joins(:comments).pluck("id", "comments" => "id")Joshua Young
Make Float distinguish between
float4andfloat8in PostgreSQL.Fixes #52742
Ryota Kitazawa, Takayuki Nagatomi
Rails 8.0.0.beta1 (September 26, 2024)
Allow
drop_tableto accept an array of table names.This will let you to drop multiple tables in a single call.
ActiveRecord::Base.lease_connection.drop_table(:users, :posts)Gabriel Sobrinho
Add support for PostgreSQL
IF NOT EXISTSvia the:if_not_existsoption on theadd_enum_valuemethod.Ariel Rzezak
When running
db:migrateon a fresh database, load the databases schemas before running migrations.Andrew Novoselac, Marek Kasztelnik
Fix an issue where
.left_outer_joinsused with multiple associations that have the same child association but different parents does not join all parents.Previously, using
.left_outer_joinswith the same child association would only join one of the parents.Now it will correctly join both parents.
Fixes #41498.
Garrett Blehm
Deprecate
unsigned_floatandunsigned_decimalshort-hand column methods.As of MySQL 8.0.17, the UNSIGNED attribute is deprecated for columns of type FLOAT, DOUBLE, and DECIMAL. Consider using a simple CHECK constraint instead for such columns.
https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html
Ryuta Kamizono
Drop MySQL 5.5 support.
MySQL 5.5 is the only version that does not support datetime with precision, which we have supported in the core. Now we support MySQL 5.6.4 or later, which is the first version to support datetime with precision.
Ryuta Kamizono
Make Active Record asynchronous queries compatible with transactional fixtures.
Previously transactional fixtures would disable asynchronous queries, because transactional fixtures impose all queries use the same connection.
Now asynchronous queries will use the connection pinned by transactional fixtures, and behave much closer to production.
Jean Boussier
Deserialize binary data before decrypting
This ensures that we call
PG::Connection.unescape_byteaon PostgreSQL before decryption.Donal McBreen
Ensure ActiveRecord::Encryption.config is always ready before access.
Previously,
::ActiveRecord::Encryptionconfiguration was deferred until::ActiveRecord::Basewas loaded. Therefore, accessing ActiveRecord::Encryption.config properties before::ActiveRecord::Basewas loaded would give incorrect results.::ActiveRecord::Encryptionnow has its own loading hook so that its configuration is set as soon as needed.When
::ActiveRecord::Baseis loaded, even lazily, it in turn triggers the loading of::ActiveRecord::Encryption, thus preserving the original behavior of having its config ready before any use of::ActiveRecord::Base.Maxime Réty
Add
TimeZoneConverter#==method, so objects will be properly compared by their type, scale, limit & precision.Address #52699.
Ruy Rocha
Add support for SQLite3 full-text-search and other virtual tables.
Previously, adding sqlite3 virtual tables messed up
schema.rb.Now, virtual tables can safely be added using
create_virtual_table.Zacharias Knudsen
Support use of alternative database interfaces via the
database_cliActiveRecordconfiguration option.Rails.application.configure do config.active_record.database_cli = { postgresql: "pgcli" } endT S Vallender
Add support for dumping table inheritance and native partitioning table definitions for PostgeSQL adapter
Justin Talbott
Add support for
::ActiveRecord::Pointtype casts usingHashvaluesThis allows
::ActiveRecord::Pointto be cast or serialized from a hash with:xand:ykeys of numeric values, mirroring the functionality of existing casts for string and array values. Both string and symbol keys are supported.class PostgresqlPoint < ActiveRecord::Base attribute :x, :point attribute :y, :point attribute :z, :point end val = PostgresqlPoint.new({ x: '(12.34, -43.21)', y: [12.34, '-43.21'], z: {x: '12.34', y: -43.21} }) ActiveRecord::Point.new(12.32, -43.21) == val.x == val.y == val.zStephen Drew
Replace
SQLite3::Database#busy_timeoutwith#busy_handler_timeout=.Provides a non-GVL-blocking, fair retry interval busy handler implementation.
Stephen Margheim
SQLite3Adapter: Translate
SQLite3::BusyExceptioninto::ActiveRecord::StatementTimeout.Matthew Nguyen
Include schema name in
enable_extensionstatements indb/schema.rb.The schema dumper will now include the schema name in generated
enable_extensionstatements if they differ from the current schema.For example, if you have a migration:
enable_extension "heroku_ext.pgcrypto" enable_extension "pg_stat_statements"then the generated schema dump will also contain:
enable_extension "heroku_ext.pgcrypto" enable_extension "pg_stat_statements"Tony Novak
Fix ActiveRecord::Encryption::EncryptedAttributeType#type to return actual cast type.
Vasiliy Ermolovich
SQLite3Adapter: Bulk insert fixtures.
Previously one insert command was executed for each fixture, now they are aggregated in a single bulk insert command.
Lázaro Nixon
PostgreSQLAdapter: Allow
disable_extensionto be called with schema-qualified name.For parity with
enable_extension, thedisable_extensionmethod can be called with a schema-qualified name (e.g.disable_extension "myschema.pgcrypto"). Note that PostgreSQL'sDROP EXTENSIONdoes not actually take a schema name (unlikeCREATE EXTENSION), so the resulting SQL statement will only name the extension, e.g.DROP EXTENSION IF EXISTS "pgcrypto".Tony Novak
Make
create_schema/drop_schemareversible in migrations.Previously,
create_schemaanddrop_schemawere irreversible migration operations.Tony Novak
Support batching using custom columns.
Product.in_batches(cursor: [:shop_id, :id]) do |relation| # do something with relation endfatkodima
Use SQLite
IMMEDIATEtransactions when possible.Transactions run against the SQLite3 adapter default to IMMEDIATE mode to improve concurrency support and avoid busy exceptions.
Stephen Margheim
Raise specific exception when a connection is not defined.
The new
ConnectionNotDefinedexception provides connection name, shard and role accessors indicating the details of the connection that was requested.Hana Harencarova, Matthew Draper
Delete the deprecated constant
ActiveRecord::ImmutableRelation.Xavier Noria
Fix duplicate callback execution when child autosaves parent with
has_oneandbelongs_to.Before, persisting a new child record with a new associated parent record would run
before_validation,after_validation,before_saveandafter_savecallbacks twice.Now, these callbacks are only executed once as expected.
Joshua Young
::ActiveRecord::Encryption::Encryptornow supports a:compressoroption to customize the compression algorithm used.module ZstdCompressor def self.deflate(data) Zstd.compress(data) end def self.inflate(data) Zstd.decompress(data) end end class User encrypts :name, compressor: ZstdCompressor endYou disable compression by passing
compress: false.class User encrypts :name, compress: false endheka1024
Add condensed
#inspectforConnectionPool,AbstractAdapter, andDatabaseConfig.Hartley McGuire
Add
.shard_keys,.sharded?, &.connected_to_all_shardsmethods.class ShardedBase < ActiveRecord::Base self.abstract_class = true connects_to shards: { shard_one: { writing: :shard_one }, shard_two: { writing: :shard_two } } end class ShardedModel < ShardedBase end ShardedModel.shard_keys => [:shard_one, :shard_two] ShardedModel.sharded? => true ShardedBase.connected_to_all_shards { ShardedModel.current_shard } => [:shard_one, :shard_two]Nony Dutton
Add a
filteroption toin_order_ofto prioritize certain values in the sorting without filtering the results by these values.Igor Depolli
Fix an issue where the IDs reader method did not return expected results for preloaded associations in models using composite primary keys.
Jay Ang
Allow to configure
strict_loading_modeglobally or within a model.Defaults to
:all, can be changed to:n_plus_one_only.Garen Torikian
Add ActiveRecord::Relation#readonly?.
Reflects if the relation has been marked as readonly.
Theodor Tonum
Improve
::ActiveRecord::Storeto raise a descriptive exception if the column is not either structured (e.g., PostgreSQLhstore+/+json, or MySQLjson) or declared serializable viaActiveRecord.store.Previously, a
NoMethodErrorwould be raised when the accessor was read or written:NoMethodError: undefined method `accessor' for an instance of ActiveRecord::Type::TextNow, a descriptive
ConfigurationErroris raised:ActiveRecord::ConfigurationError: the column 'metadata' has not been configured as a store. Please make sure the column is declared serializable via 'ActiveRecord.store' or, if your database supports it, use a structured column type like hstore or json.Mike Dalessio
Fix inference of association model on nested models with the same demodularized name.
E.g. with the following setup:
class Nested::Post < ApplicationRecord has_one :post, through: :other endBefore,
#postwould infer the model asNested::Post, but now it correctly infersPost.Joshua Young
Add public method for checking if a table is ignored by the schema cache.
Previously, an application would need to reimplement
ignored_table?from the schema cache class to check if a table was set to be ignored. This adds a public method to support this and updates the schema cache to use that directly.ActiveRecord.schema_cache_ignored_tables = ["developers"] ActiveRecord.schema_cache_ignored_table?("developers") #=> trueEileen M. Uchitelle
Please check [7-2-stable]) for previous changes.