Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package rubygem-activerecord-8.0 for 
openSUSE:Factory checked in at 2025-08-22 17:49:22
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-activerecord-8.0 (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-activerecord-8.0.new.29662 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-activerecord-8.0"

Fri Aug 22 17:49:22 2025 rev:5 rq:1300933 version:8.0.2.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/rubygem-activerecord-8.0/rubygem-activerecord-8.0.changes
        2025-08-21 17:00:34.765106206 +0200
+++ 
/work/SRC/openSUSE:Factory/.rubygem-activerecord-8.0.new.29662/rubygem-activerecord-8.0.changes
     2025-08-22 17:50:56.627798810 +0200
@@ -1,0 +2,6 @@
+Thu Aug 21 10:20:54 UTC 2025 - Marcus Rueckert <mrueck...@suse.de>
+
+- Drop CVE-2025-55193.patch:
+  it is already handled in the version update
+
+-------------------------------------------------------------------
@@ -5,0 +12,6 @@
+
+-------------------------------------------------------------------
+Thu Aug 14 00:25:11 UTC 2025 - Marcus Rueckert <mrueck...@suse.de>
+
+- Update to version 8.0.2.1:
+  
https://rubyonrails.org/2025/8/13/Rails-Versions-8-0-2-1-7-2-2-2-and-7-1-5-2-have-been-released

Old:
----
  CVE-2025-55193.patch
  activerecord-8.0.1.gem

New:
----
  activerecord-8.0.2.1.gem

----------(Old B)----------
  Old:
- Drop CVE-2025-55193.patch:
  it is already handled in the version update
----------(Old E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-activerecord-8.0.spec ++++++
--- /var/tmp/diff_new_pack.gMLZfF/_old  2025-08-22 17:50:57.363829481 +0200
+++ /var/tmp/diff_new_pack.gMLZfF/_new  2025-08-22 17:50:57.367829648 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package rubygem-activerecord-8.0
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2025 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -24,7 +24,7 @@
 #
 
 Name:           rubygem-activerecord-8.0
-Version:        8.0.1
+Version:        8.0.2.1
 Release:        0
 %define mod_name activerecord
 %define mod_full_name %{mod_name}-%{version}
@@ -36,7 +36,6 @@
 URL:            https://rubyonrails.org
 Source:         https://rubygems.org/gems/%{mod_full_name}.gem
 Source1:        gem2rpm.yml
-Patch0:         CVE-2025-55193.patch
 Summary:        Object-relational mapper framework (part of Rails)
 License:        MIT
 
@@ -46,10 +45,6 @@
 aggregations, migrations, and testing come baked-in.
 
 %prep
-%gem_unpack
-%patch -P 0 -p1
-find -type f -print0 | xargs -0 touch -r %{S:0}
-%gem_build
 
 %build
 

++++++ activerecord-8.0.1.gem -> activerecord-8.0.2.1.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md
--- old/CHANGELOG.md    2024-12-13 21:02:34.000000000 +0100
+++ new/CHANGELOG.md    1980-01-02 01:00:00.000000000 +0100
@@ -1,6 +1,151 @@
+## 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) ##
+
+*   No changes.
+
+
+## Rails 8.0.2 (March 12, 2025) ##
+
+*   Fix inverting `rename_enum_value` when `:from`/`:to` are provided.
+
+    *fatkodima*
+
+*   Prevent persisting invalid record.
+
+    *Edouard Chin*
+
+*   Fix inverting `drop_table` without options.
+
+    *fatkodima*
+
+*   Fix count with group by qualified name on loaded relation.
+
+    *Ryuta Kamizono*
+
+*   Fix `sum` with qualified name on loaded relation.
+
+    *Chris Gunther*
+
+*   The SQLite3 adapter quotes non-finite Numeric values 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::ConnectionFailed`
+    and 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 method 
`key?' for nil`
+    or `TypeError: 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.
+
+    ```ruby
+    Post.async_count
+    ActiveSupport::Notifications.subscribed(->(*) { "Will never reach here" }) 
do
+      Post.count
+    end
+    ```
+
+    In 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.
+
+    ```ruby
+    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).first
+    ```
+
+    The above example would result in `ActiveRecord::StatementInvalid` because 
the
+    `active` scope 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:
+
+    ```ruby
+    Post.create!(author: User.find(1)) # Fail if user is invalid
+    ```
+
+    *Jean 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 :restrict action for MySQ
+*   Fix removing foreign keys with :restrict action for MySQL.
 
     *fatkodima*
 
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/associations/alias_tracker.rb 
new/lib/active_record/associations/alias_tracker.rb
--- old/lib/active_record/associations/alias_tracker.rb 2024-12-13 
21:02:34.000000000 +0100
+++ new/lib/active_record/associations/alias_tracker.rb 1980-01-02 
01:00:00.000000000 +0100
@@ -26,16 +26,18 @@
       end
 
       def self.initial_count_for(connection, name, table_joins)
-        quoted_name = nil
+        quoted_name_escaped = nil
+        name_escaped = nil
 
         counts = table_joins.map do |join|
           if join.is_a?(Arel::Nodes::StringJoin)
-            # quoted_name should be case ignored as some database adapters 
(Oracle) return quoted name in uppercase
-            quoted_name ||= connection.quote_table_name(name)
+            # quoted_name_escaped should be case ignored as some database 
adapters (Oracle) return quoted name in uppercase
+            quoted_name_escaped ||= 
Regexp.escape(connection.quote_table_name(name))
+            name_escaped ||= Regexp.escape(name)
 
             # Table names + table aliases
             join.left.scan(
-              /JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name}|#{name})\sON/i
+              
/JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name_escaped}|#{name_escaped})\sON/i
             ).size
           elsif join.is_a?(Arel::Nodes::Join)
             join.left.name == name ? 1 : 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/associations/join_dependency/join_association.rb 
new/lib/active_record/associations/join_dependency/join_association.rb
--- old/lib/active_record/associations/join_dependency/join_association.rb      
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/associations/join_dependency/join_association.rb      
1980-01-02 01:00:00.000000000 +0100
@@ -38,41 +38,39 @@
             chain << [reflection, table]
           end
 
-          base_klass.with_connection do |connection|
-            # The chain starts with the target table, but we want to end with 
it here (makes
-            # more sense in this context), so we reverse
-            chain.reverse_each do |reflection, table|
-              klass = reflection.klass
-
-              scope = reflection.join_scope(table, foreign_table, 
foreign_klass)
-
-              unless scope.references_values.empty?
-                associations = scope.eager_load_values | scope.includes_values
-
-                unless associations.empty?
-                  scope.joins! scope.construct_join_dependency(associations, 
Arel::Nodes::OuterJoin)
-                end
-              end
+          # The chain starts with the target table, but we want to end with it 
here (makes
+          # more sense in this context), so we reverse
+          chain.reverse_each do |reflection, table|
+            klass = reflection.klass
+
+            scope = reflection.join_scope(table, foreign_table, foreign_klass)
 
-              arel = scope.arel(alias_tracker.aliases)
-              nodes = arel.constraints.first
+            unless scope.references_values.empty?
+              associations = scope.eager_load_values | scope.includes_values
 
-              if nodes.is_a?(Arel::Nodes::And)
-                others = nodes.children.extract! do |node|
-                  !Arel.fetch_attribute(node) { |attr| attr.relation.name == 
table.name }
-                end
+              unless associations.empty?
+                scope.joins! scope.construct_join_dependency(associations, 
Arel::Nodes::OuterJoin)
               end
+            end
 
-              joins << join_type.new(table, Arel::Nodes::On.new(nodes))
+            arel = scope.arel(alias_tracker.aliases)
+            nodes = arel.constraints.first
 
-              if others && !others.empty?
-                joins.concat arel.join_sources
-                append_constraints(connection, joins.last, others)
+            if nodes.is_a?(Arel::Nodes::And)
+              others = nodes.children.extract! do |node|
+                !Arel.fetch_attribute(node) { |attr| attr.relation.name == 
table.name }
               end
+            end
+
+            joins << join_type.new(table, Arel::Nodes::On.new(nodes))
 
-              # The current table in this iteration becomes the foreign table 
in the next
-              foreign_table, foreign_klass = table, klass
+            if others && !others.empty?
+              joins.concat arel.join_sources
+              append_constraints(joins.last, others)
             end
+
+            # The current table in this iteration becomes the foreign table in 
the next
+            foreign_table, foreign_klass = table, klass
           end
 
           joins
@@ -91,10 +89,10 @@
         end
 
         private
-          def append_constraints(connection, join, constraints)
+          def append_constraints(join, constraints)
             if join.is_a?(Arel::Nodes::StringJoin)
               join_string = Arel::Nodes::And.new(constraints.unshift join.left)
-              join.left = Arel.sql(connection.visitor.compile(join_string))
+              join.left = join_string
             else
               right = join.right
               right.expr = Arel::Nodes::And.new(constraints.unshift right.expr)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/attributes.rb 
new/lib/active_record/attributes.rb
--- old/lib/active_record/attributes.rb 2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/attributes.rb 1980-01-02 01:00:00.000000000 +0100
@@ -178,8 +178,8 @@
       #       @currency_converter = currency_converter
       #     end
       #
-      #     # value will be the result of +deserialize+ or
-      #     # +cast+. Assumed to be an instance of +Money+ in
+      #     # value will be the result of #deserialize or
+      #     # #cast. Assumed to be an instance of Money in
       #     # this case.
       #     def serialize(value)
       #       value_in_bitcoins = 
@currency_converter.convert_to_bitcoins(value)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/autosave_association.rb 
new/lib/active_record/autosave_association.rb
--- old/lib/active_record/autosave_association.rb       2024-12-13 
21:02:34.000000000 +0100
+++ new/lib/active_record/autosave_association.rb       1980-01-02 
01:00:00.000000000 +0100
@@ -372,19 +372,29 @@
         return true if record.destroyed? || (association.options[:autosave] && 
record.marked_for_destruction?)
 
         context = validation_context if custom_validation_context?
+        return true if record.valid?(context)
 
-        unless valid = record.valid?(context)
-          if association.options[:autosave]
-            record.errors.each { |error|
-              self.errors.objects.append(
-                Associations::NestedError.new(association, error)
-              )
-            }
-          else
-            errors.add(association.reflection.name)
-          end
+        if record.changed? || record.new_record? || context
+          associated_errors = record.errors.objects
+        else
+          # If there are existing invalid records in the DB, we should still 
be able to reference them.
+          # Unless a record (no matter where in the association chain) is 
invalid and is being changed.
+          associated_errors = record.errors.objects.select { |error| 
error.is_a?(Associations::NestedError) }
         end
-        valid
+
+        if association.options[:autosave]
+          return if equal?(record)
+
+          associated_errors.each { |error|
+            errors.objects.append(
+              Associations::NestedError.new(association, error)
+            )
+          }
+        elsif associated_errors.any?
+          errors.add(association.reflection.name)
+        end
+
+        errors.any?
       end
 
       # Is used as an around_save callback to check while saving a collection
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/abstract/connection_handler.rb 
new/lib/active_record/connection_adapters/abstract/connection_handler.rb
--- old/lib/active_record/connection_adapters/abstract/connection_handler.rb    
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/abstract/connection_handler.rb    
1980-01-02 01:00:00.000000000 +0100
@@ -54,19 +54,22 @@
     # about the model. The model needs to pass a connection specification name 
to the handler,
     # in order to look up the correct connection pool.
     class ConnectionHandler
-      class StringConnectionName # :nodoc:
-        attr_reader :name
-
-        def initialize(name)
+      class ConnectionDescriptor # :nodoc:
+        def initialize(name, primary = false)
           @name = name
+          @primary = primary
+        end
+
+        def name
+          primary_class? ? "ActiveRecord::Base" : @name
         end
 
         def primary_class?
-          false
+          @primary
         end
 
         def current_preventing_writes
-          false
+          ActiveRecord::Base.preventing_writes?(@name)
         end
       end
 
@@ -115,7 +118,7 @@
         pool_config = resolve_pool_config(config, owner_name, role, shard)
         db_config = pool_config.db_config
 
-        pool_manager = set_pool_manager(pool_config.connection_name)
+        pool_manager = set_pool_manager(pool_config.connection_descriptor)
 
         # If there is an existing pool with the same values as the pool_config
         # don't remove the connection. Connections should only be removed if 
we are
@@ -127,8 +130,8 @@
           # Update the pool_config's connection class if it differs. This is 
used
           # for ensuring that ActiveRecord::Base and the 
primary_abstract_class use
           # the same pool. Without this granular swapping will not work 
correctly.
-          if owner_name.primary_class? && 
(existing_pool_config.connection_class != owner_name)
-            existing_pool_config.connection_class = owner_name
+          if owner_name.primary_class? && 
(existing_pool_config.connection_descriptor != owner_name)
+            existing_pool_config.connection_descriptor = owner_name
           end
 
           existing_pool_config.pool
@@ -137,7 +140,7 @@
           pool_manager.set_pool_config(role, shard, pool_config)
 
           payload = {
-            connection_name: pool_config.connection_name,
+            connection_name: pool_config.connection_descriptor.name,
             role: role,
             shard: shard,
             config: db_config.configuration_hash
@@ -242,8 +245,8 @@
         end
 
         # Get the existing pool manager or initialize and assign a new one.
-        def set_pool_manager(connection_name)
-          connection_name_to_pool_manager[connection_name] ||= PoolManager.new
+        def set_pool_manager(connection_descriptor)
+          connection_name_to_pool_manager[connection_descriptor.name] ||= 
PoolManager.new
         end
 
         def pool_managers
@@ -278,9 +281,9 @@
 
         def determine_owner_name(owner_name, config)
           if owner_name.is_a?(String) || owner_name.is_a?(Symbol)
-            StringConnectionName.new(owner_name.to_s)
+            ConnectionDescriptor.new(owner_name.to_s)
           elsif config.is_a?(Symbol)
-            StringConnectionName.new(config.to_s)
+            ConnectionDescriptor.new(config.to_s)
           else
             owner_name
           end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/abstract/connection_pool.rb 
new/lib/active_record/connection_adapters/abstract/connection_pool.rb
--- old/lib/active_record/connection_adapters/abstract/connection_pool.rb       
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/abstract/connection_pool.rb       
1980-01-02 01:00:00.000000000 +0100
@@ -36,7 +36,7 @@
       end
 
       def schema_cache; end
-      def connection_class; end
+      def connection_descriptor; end
       def checkin(_); end
       def remove(_); end
       def async_executor; end
@@ -364,8 +364,8 @@
         clean
       end
 
-      def connection_class # :nodoc:
-        pool_config.connection_class
+      def connection_descriptor # :nodoc:
+        pool_config.connection_descriptor
       end
 
       # Returns true if there is an open connection being used for the current 
thread.
@@ -545,20 +545,25 @@
       # Raises:
       # - ActiveRecord::ConnectionTimeoutError no connection can be obtained 
from the pool.
       def checkout(checkout_timeout = @checkout_timeout)
-        if @pinned_connection
-          @pinned_connection.lock.synchronize do
-            synchronize do
+        return checkout_and_verify(acquire_connection(checkout_timeout)) 
unless @pinned_connection
+
+        @pinned_connection.lock.synchronize do
+          synchronize do
+            # The pinned connection may have been cleaned up before we 
synchronized, so check if it is still present
+            if @pinned_connection
               @pinned_connection.verify!
+
               # Any leased connection must be in @connections otherwise
               # some methods like #connected? won't behave correctly
               unless @connections.include?(@pinned_connection)
                 @connections << @pinned_connection
               end
+
+              @pinned_connection
+            else
+              checkout_and_verify(acquire_connection(checkout_timeout))
             end
           end
-          @pinned_connection
-        else
-          checkout_and_verify(acquire_connection(checkout_timeout))
         end
       end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/abstract/schema_definitions.rb 
new/lib/active_record/connection_adapters/abstract/schema_definitions.rb
--- old/lib/active_record/connection_adapters/abstract/schema_definitions.rb    
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/abstract/schema_definitions.rb    
1980-01-02 01:00:00.000000000 +0100
@@ -434,7 +434,7 @@
       #
       # == Examples
       #
-      #  # Assuming +td+ is an instance of TableDefinition
+      #  # Assuming `td` is an instance of TableDefinition
       #  td.column(:granted, :boolean, index: true)
       #
       # == Short-hand examples
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/abstract_adapter.rb 
new/lib/active_record/connection_adapters/abstract_adapter.rb
--- old/lib/active_record/connection_adapters/abstract_adapter.rb       
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/abstract_adapter.rb       
1980-01-02 01:00:00.000000000 +0100
@@ -150,7 +150,6 @@
         end
 
         @owner = nil
-        @instrumenter = ActiveSupport::Notifications.instrumenter
         @pool = ActiveRecord::ConnectionAdapters::NullPool.new
         @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
         @visitor = arel_visitor
@@ -168,6 +167,7 @@
         @default_timezone = 
self.class.validate_default_timezone(@config[:default_timezone])
 
         @raw_connection_dirty = false
+        @last_activity = nil
         @verified = false
       end
 
@@ -190,19 +190,6 @@
         end
       end
 
-      EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
-      EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
-      private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
-      def with_instrumenter(instrumenter, &block) # :nodoc:
-        Thread.handle_interrupt(EXCEPTION_NEVER) do
-          previous_instrumenter = @instrumenter
-          @instrumenter = instrumenter
-          Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
-        ensure
-          @instrumenter = previous_instrumenter
-        end
-      end
-
       def check_if_write_query(sql) # :nodoc:
         if preventing_writes? && write_query?(sql)
           raise ActiveRecord::ReadOnlyError, "Write query attempted while in 
readonly mode: #{sql}"
@@ -217,6 +204,10 @@
         (@config[:connection_retries] || 1).to_i
       end
 
+      def verify_timeout
+        (@config[:verify_timeout] || 2).to_i
+      end
+
       def retry_deadline
         if @config[:retry_deadline]
           @config[:retry_deadline].to_f
@@ -235,9 +226,9 @@
       # the value of +current_preventing_writes+.
       def preventing_writes?
         return true if replica?
-        return false if connection_class.nil?
+        return false if connection_descriptor.nil?
 
-        connection_class.current_preventing_writes
+        connection_descriptor.current_preventing_writes
       end
 
       def prepared_statements?
@@ -288,8 +279,8 @@
         @owner = ActiveSupport::IsolatedExecutionState.context
       end
 
-      def connection_class # :nodoc:
-        @pool.connection_class
+      def connection_descriptor # :nodoc:
+        @pool.connection_descriptor
       end
 
       # The role (e.g. +:writing+) for the current connection. In a
@@ -343,6 +334,13 @@
         Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
       end
 
+      # Seconds since this connection last communicated with the server
+      def seconds_since_last_activity # :nodoc:
+        if @raw_connection && @last_activity
+          Process.clock_gettime(Process::CLOCK_MONOTONIC) - @last_activity
+        end
+      end
+
       def unprepared_statement
         cache = prepared_statements_disabled_cache.add?(object_id) if 
@prepared_statements
         yield
@@ -670,11 +668,12 @@
 
           enable_lazy_transactions!
           @raw_connection_dirty = false
+          @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
           @verified = true
 
           reset_transaction(restore: restore_transactions) do
             clear_cache!(new_connection: true)
-            configure_connection
+            attempt_configure_connection
           end
         rescue => original_exception
           translated_exception = translate_exception_class(original_exception, 
nil, nil)
@@ -689,6 +688,7 @@
             end
           end
 
+          @last_activity = nil
           @verified = false
 
           raise translated_exception
@@ -726,7 +726,7 @@
       def reset!
         clear_cache!(new_connection: true)
         reset_transaction
-        configure_connection
+        attempt_configure_connection
       end
 
       # Removes the connection from the pool and disconnect it.
@@ -762,7 +762,8 @@
             if @unconfigured_connection
               @raw_connection = @unconfigured_connection
               @unconfigured_connection = nil
-              configure_connection
+              attempt_configure_connection
+              @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
               @verified = true
               return
             end
@@ -992,6 +993,9 @@
             if @verified
               # Cool, we're confident the connection's ready to use. (Note 
this might have
               # become true during the above #materialize_transactions.)
+            elsif (last_activity = seconds_since_last_activity) && 
last_activity < verify_timeout
+              # We haven't actually verified the connection since we acquired 
it, but it
+              # has been used very recently. We're going to assume it's still 
okay.
             elsif reconnectable
               if allow_retry
                 # Not sure about the connection yet, but if anything goes 
wrong we can
@@ -1033,6 +1037,7 @@
                 # Barring a known-retryable error inside the query (regardless 
of
                 # whether we were in a _position_ to retry it), we should 
infer that
                 # there's likely a real problem with the connection.
+                @last_activity = nil
                 @verified = false
               end
 
@@ -1047,6 +1052,7 @@
         # `with_raw_connection` block only when the block is guaranteed to
         # exercise the raw connection.
         def verified!
+          @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
           @verified = true
         end
 
@@ -1126,7 +1132,7 @@
         end
 
         def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: 
false, &block) # :doc:
-          @instrumenter.instrument(
+          instrumenter.instrument(
             "sql.active_record",
             sql:               sql,
             name:              name,
@@ -1142,6 +1148,10 @@
           raise ex.set_query(sql, binds)
         end
 
+        def instrumenter # :nodoc:
+          ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] 
||= ActiveSupport::Notifications.instrumenter
+        end
+
         def translate_exception(exception, message:, sql:, binds:)
           # override in derived class
           case exception
@@ -1203,6 +1213,13 @@
           check_version
         end
 
+        def attempt_configure_connection
+          configure_connection
+        rescue
+          disconnect!
+          raise
+        end
+
         def default_prepared_statements
           true
         end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/abstract_mysql_adapter.rb 
new/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
--- old/lib/active_record/connection_adapters/abstract_mysql_adapter.rb 
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/abstract_mysql_adapter.rb 
1980-01-02 01:00:00.000000000 +0100
@@ -174,6 +174,10 @@
         mariadb? && database_version >= "10.5.0"
       end
 
+      def return_value_after_insert?(column) # :nodoc:
+        supports_insert_returning? ? column.auto_populated? : 
column.auto_increment?
+      end
+
       def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
         query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") 
== 1
       end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/mysql2_adapter.rb 
new/lib/active_record/connection_adapters/mysql2_adapter.rb
--- old/lib/active_record/connection_adapters/mysql2_adapter.rb 2024-12-13 
21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/mysql2_adapter.rb 1980-01-02 
01:00:00.000000000 +0100
@@ -106,7 +106,14 @@
       end
 
       def active?
-        connected? && @lock.synchronize { @raw_connection&.ping } || false
+        if connected?
+          @lock.synchronize do
+            if @raw_connection&.ping
+              verified!
+              true
+            end
+          end
+        end || false
       end
 
       alias :reset! :reconnect!
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/connection_adapters/pool_config.rb 
new/lib/active_record/connection_adapters/pool_config.rb
--- old/lib/active_record/connection_adapters/pool_config.rb    2024-12-13 
21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/pool_config.rb    1980-01-02 
01:00:00.000000000 +0100
@@ -5,9 +5,8 @@
     class PoolConfig # :nodoc:
       include MonitorMixin
 
-      attr_reader :db_config, :role, :shard
+      attr_reader :db_config, :role, :shard, :connection_descriptor
       attr_writer :schema_reflection, :server_version
-      attr_accessor :connection_class
 
       def schema_reflection
         @schema_reflection ||= 
SchemaReflection.new(db_config.lazy_schema_cache_path)
@@ -29,7 +28,7 @@
       def initialize(connection_class, db_config, role, shard)
         super()
         @server_version = nil
-        @connection_class = connection_class
+        self.connection_descriptor = connection_class
         @db_config = db_config
         @role = role
         @shard = shard
@@ -41,11 +40,12 @@
         @server_version || synchronize { @server_version ||= 
connection.get_database_version }
       end
 
-      def connection_name
-        if connection_class.primary_class?
-          "ActiveRecord::Base"
+      def connection_descriptor=(connection_descriptor)
+        case connection_descriptor
+        when ConnectionHandler::ConnectionDescriptor
+          @connection_descriptor = connection_descriptor
         else
-          connection_class.name
+          @connection_descriptor = 
ConnectionHandler::ConnectionDescriptor.new(connection_descriptor.name, 
connection_descriptor.primary_class?)
         end
       end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/postgresql/schema_definitions.rb 
new/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
--- old/lib/active_record/connection_adapters/postgresql/schema_definitions.rb  
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/postgresql/schema_definitions.rb  
1980-01-02 01:00:00.000000000 +0100
@@ -308,8 +308,8 @@
         #  t.exclusion_constraint("price WITH =, availability_range WITH &&", 
using: :gist, name: "price_check")
         #
         # See 
{connection.add_exclusion_constraint}[rdoc-ref:SchemaStatements#add_exclusion_constraint]
-        def exclusion_constraint(*args)
-          @base.add_exclusion_constraint(name, *args)
+        def exclusion_constraint(...)
+          @base.add_exclusion_constraint(name, ...)
         end
 
         # Removes the given exclusion constraint from the table.
@@ -317,8 +317,8 @@
         #  t.remove_exclusion_constraint(name: "price_check")
         #
         # See 
{connection.remove_exclusion_constraint}[rdoc-ref:SchemaStatements#remove_exclusion_constraint]
-        def remove_exclusion_constraint(*args)
-          @base.remove_exclusion_constraint(name, *args)
+        def remove_exclusion_constraint(...)
+          @base.remove_exclusion_constraint(name, ...)
         end
 
         # Adds a unique constraint.
@@ -326,8 +326,8 @@
         #  t.unique_constraint(:position, name: 'unique_position', deferrable: 
:deferred, nulls_not_distinct: true)
         #
         # See 
{connection.add_unique_constraint}[rdoc-ref:SchemaStatements#add_unique_constraint]
-        def unique_constraint(*args)
-          @base.add_unique_constraint(name, *args)
+        def unique_constraint(...)
+          @base.add_unique_constraint(name, ...)
         end
 
         # Removes the given unique constraint from the table.
@@ -335,8 +335,8 @@
         #  t.remove_unique_constraint(name: "unique_position")
         #
         # See 
{connection.remove_unique_constraint}[rdoc-ref:SchemaStatements#remove_unique_constraint]
-        def remove_unique_constraint(*args)
-          @base.remove_unique_constraint(name, *args)
+        def remove_unique_constraint(...)
+          @base.remove_unique_constraint(name, ...)
         end
 
         # Validates the given constraint on the table.
@@ -345,8 +345,8 @@
         #  t.validate_constraint "price_check"
         #
         # See 
{connection.validate_constraint}[rdoc-ref:SchemaStatements#validate_constraint]
-        def validate_constraint(*args)
-          @base.validate_constraint(name, *args)
+        def validate_constraint(...)
+          @base.validate_constraint(name, ...)
         end
 
         # Validates the given check constraint on the table
@@ -355,8 +355,8 @@
         #  t.validate_check_constraint name: "price_check"
         #
         # See 
{connection.validate_check_constraint}[rdoc-ref:SchemaStatements#validate_check_constraint]
-        def validate_check_constraint(*args)
-          @base.validate_check_constraint(name, *args)
+        def validate_check_constraint(...)
+          @base.validate_check_constraint(name, ...)
         end
       end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/postgresql/schema_dumper.rb 
new/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
--- old/lib/active_record/connection_adapters/postgresql/schema_dumper.rb       
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/postgresql/schema_dumper.rb       
1980-01-02 01:00:00.000000000 +0100
@@ -22,7 +22,7 @@
               stream.puts "  # Custom types defined in this database."
               stream.puts "  # Note that some types may not work with other 
database engines. Be careful if changing database."
               types.sort.each do |name, values|
-                stream.puts "  create_enum #{name.inspect}, 
#{values.split(",").inspect}"
+                stream.puts "  create_enum #{name.inspect}, #{values.inspect}"
               end
               stream.puts
             end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/postgresql_adapter.rb 
new/lib/active_record/connection_adapters/postgresql_adapter.rb
--- old/lib/active_record/connection_adapters/postgresql_adapter.rb     
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/postgresql_adapter.rb     
1980-01-02 01:00:00.000000000 +0100
@@ -349,6 +349,7 @@
         @lock.synchronize do
           return false unless @raw_connection
           @raw_connection.query ";"
+          verified!
         end
         true
       rescue PG::Error
@@ -520,7 +521,7 @@
             type.typname AS name,
             type.OID AS oid,
             n.nspname AS schema,
-            string_agg(enum.enumlabel, ',' ORDER BY enum.enumsortorder) AS 
value
+            array_agg(enum.enumlabel ORDER BY enum.enumsortorder) AS value
           FROM pg_enum AS enum
           JOIN pg_type AS type ON (type.oid = enum.enumtypid)
           JOIN pg_namespace n ON type.typnamespace = n.oid
@@ -633,7 +634,11 @@
       # Returns the version of the connected PostgreSQL server.
       def get_database_version # :nodoc:
         with_raw_connection do |conn|
-          conn.server_version
+          version = conn.server_version
+          if version == 0
+            raise ActiveRecord::ConnectionFailed, "Could not determine 
PostgreSQL version"
+          end
+          version
         end
       end
       alias :postgresql_version :database_version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/sqlite3/quoting.rb 
new/lib/active_record/connection_adapters/sqlite3/quoting.rb
--- old/lib/active_record/connection_adapters/sqlite3/quoting.rb        
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/sqlite3/quoting.rb        
1980-01-02 01:00:00.000000000 +0100
@@ -50,6 +50,19 @@
           end
         end
 
+        def quote(value) # :nodoc:
+          case value
+          when Numeric
+            if value.finite?
+              super
+            else
+              "'#{value}'"
+            end
+          else
+            super
+          end
+        end
+
         def quote_string(s)
           ::SQLite3::Database.quote(s)
         end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/sqlite3_adapter.rb 
new/lib/active_record/connection_adapters/sqlite3_adapter.rb
--- old/lib/active_record/connection_adapters/sqlite3_adapter.rb        
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/sqlite3_adapter.rb        
1980-01-02 01:00:00.000000000 +0100
@@ -207,7 +207,12 @@
         !(@raw_connection.nil? || @raw_connection.closed?)
       end
 
-      alias_method :active?, :connected?
+      def active?
+        if connected?
+          verified!
+          true
+        end
+      end
 
       alias :reset! :reconnect!
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/active_record/connection_adapters/trilogy_adapter.rb 
new/lib/active_record/connection_adapters/trilogy_adapter.rb
--- old/lib/active_record/connection_adapters/trilogy_adapter.rb        
2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/connection_adapters/trilogy_adapter.rb        
1980-01-02 01:00:00.000000000 +0100
@@ -121,7 +121,7 @@
       end
 
       def active?
-        connected? && @lock.synchronize { @raw_connection&.ping } || false
+        connected? && @lock.synchronize { @raw_connection&.ping; verified! } 
|| false
       rescue ::Trilogy::Error
         false
       end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/core.rb 
new/lib/active_record/core.rb
--- old/lib/active_record/core.rb       2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/core.rb       1980-01-02 01:00:00.000000000 +0100
@@ -202,6 +202,17 @@
         false
       end
 
+      # Intended to behave like `.current_preventing_writes` given the class 
name as input.
+      # See PoolConfig and ConnectionHandler::ConnectionDescriptor.
+      def self.preventing_writes?(class_name) # :nodoc:
+        connected_to_stack.reverse_each do |hash|
+          return hash[:prevent_writes] if !hash[:prevent_writes].nil? && 
hash[:klasses].include?(Base)
+          return hash[:prevent_writes] if !hash[:prevent_writes].nil? && 
hash[:klasses].any? { |klass| klass.name == class_name }
+        end
+
+        false
+      end
+
       def self.connected_to_stack # :nodoc:
         if connected_to_stack = 
ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack]
           connected_to_stack
@@ -266,7 +277,7 @@
         return super if StatementCache.unsupported_value?(id)
 
         cached_find_by([primary_key], [id]) ||
-          raise(RecordNotFound.new("Couldn't find #{name} with 
'#{primary_key}'=#{id}", name, primary_key, id))
+          raise(RecordNotFound.new("Couldn't find #{name} with 
'#{primary_key}'=#{id.inspect}", name, primary_key, id))
       end
 
       def find_by(*args) # :nodoc:
@@ -727,11 +738,29 @@
       @strict_loading_mode == :all
     end
 
-    # Marks this record as read only.
+    # Prevents records from being written to the database:
+    #
+    #   customer = Customer.new
+    #   customer.readonly!
+    #   customer.save # raises ActiveRecord::ReadOnlyRecord
     #
     #   customer = Customer.first
     #   customer.readonly!
-    #   customer.save # Raises an ActiveRecord::ReadOnlyRecord
+    #   customer.update(name: 'New Name') # raises ActiveRecord::ReadOnlyRecord
+    #
+    # Read-only records cannot be deleted from the database either:
+    #
+    #   customer = Customer.first
+    #   customer.readonly!
+    #   customer.destroy # raises ActiveRecord::ReadOnlyRecord
+    #
+    # Please, note that the objects themselves are still mutable in memory:
+    #
+    #   customer = Customer.new
+    #   customer.readonly!
+    #   customer.name = 'New Name' # OK
+    #
+    # but you won't be able to persist the changes.
     def readonly!
       @readonly = true
     end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/counter_cache.rb 
new/lib/active_record/counter_cache.rb
--- old/lib/active_record/counter_cache.rb      2024-12-13 21:02:34.000000000 
+0100
+++ new/lib/active_record/counter_cache.rb      1980-01-02 01:00:00.000000000 
+0100
@@ -28,7 +28,7 @@
       #   # For the Post with id #1, reset the comments_count
       #   Post.reset_counters(1, :comments)
       #
-      #   # Like above, but also touch the +updated_at+ and/or +updated_on+
+      #   # Like above, but also touch the updated_at and/or updated_on
       #   # attributes.
       #   Post.reset_counters(1, :comments, touch: true)
       def reset_counters(id, *counters, touch: nil)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/delegated_type.rb 
new/lib/active_record/delegated_type.rb
--- old/lib/active_record/delegated_type.rb     2024-12-13 21:02:34.000000000 
+0100
+++ new/lib/active_record/delegated_type.rb     1980-01-02 01:00:00.000000000 
+0100
@@ -181,16 +181,16 @@
     #     delegated_type :entryable, types: %w[ Message Comment ], dependent: 
:destroy
     #   end
     #
-    #   Entry#entryable_class # => +Message+ or +Comment+
-    #   Entry#entryable_name  # => "message" or "comment"
-    #   Entry.messages        # => Entry.where(entryable_type: "Message")
-    #   Entry#message?        # => true when entryable_type == "Message"
-    #   Entry#message         # => returns the message record, when 
entryable_type == "Message", otherwise nil
-    #   Entry#message_id      # => returns entryable_id, when entryable_type 
== "Message", otherwise nil
-    #   Entry.comments        # => Entry.where(entryable_type: "Comment")
-    #   Entry#comment?        # => true when entryable_type == "Comment"
-    #   Entry#comment         # => returns the comment record, when 
entryable_type == "Comment", otherwise nil
-    #   Entry#comment_id      # => returns entryable_id, when entryable_type 
== "Comment", otherwise nil
+    #   @entry.entryable_class # => Message or Comment
+    #   @entry.entryable_name  # => "message" or "comment"
+    #   Entry.messages         # => Entry.where(entryable_type: "Message")
+    #   @entry.message?        # => true when entryable_type == "Message"
+    #   @entry.message         # => returns the message record, when 
entryable_type == "Message", otherwise nil
+    #   @entry.message_id      # => returns entryable_id, when entryable_type 
== "Message", otherwise nil
+    #   Entry.comments         # => Entry.where(entryable_type: "Comment")
+    #   @entry.comment?        # => true when entryable_type == "Comment"
+    #   @entry.comment         # => returns the comment record, when 
entryable_type == "Comment", otherwise nil
+    #   @entry.comment_id      # => returns entryable_id, when entryable_type 
== "Comment", otherwise nil
     #
     # You can also declare namespaced types:
     #
@@ -199,25 +199,25 @@
     #   end
     #
     #   Entry.access_notice_messages
-    #   entry.access_notice_message
-    #   entry.access_notice_message?
+    #   @entry.access_notice_message
+    #   @entry.access_notice_message?
     #
     # === Options
     #
     # The +options+ are passed directly to the +belongs_to+ call, so this is 
where you declare +dependent+ etc.
     # The following options can be included to specialize the behavior of the 
delegated type convenience methods.
     #
-    # [:foreign_key]
+    # [+:foreign_key+]
     #   Specify the foreign key used for the convenience methods. By default 
this is guessed to be the passed
     #   +role+ with an "_id" suffix. So a class that defines a
     #   <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> 
association will use "entryable_id" as
     #   the default <tt>:foreign_key</tt>.
-    # [:foreign_type]
+    # [+:foreign_type+]
     #   Specify the column used to store the associated object's type. By 
default this is inferred to be the passed
     #   +role+ with a "_type" suffix. A class that defines a
     #   <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> 
association will use "entryable_type" as
     #   the default <tt>:foreign_type</tt>.
-    # [:primary_key]
+    # [+:primary_key+]
     #   Specify the method that returns the primary key of associated object 
used for the convenience methods.
     #   By default this is +id+.
     #
@@ -226,8 +226,8 @@
     #     delegated_type :entryable, types: %w[ Message Comment ], 
primary_key: :uuid, foreign_key: :entryable_uuid
     #   end
     #
-    #   Entry#message_uuid      # => returns entryable_uuid, when 
entryable_type == "Message", otherwise nil
-    #   Entry#comment_uuid      # => returns entryable_uuid, when 
entryable_type == "Comment", otherwise nil
+    #   @entry.message_uuid # => returns entryable_uuid, when entryable_type 
== "Message", otherwise nil
+    #   @entry.comment_uuid # => returns entryable_uuid, when entryable_type 
== "Comment", otherwise nil
     def delegated_type(role, types:, **options)
       belongs_to role, options.delete(:scope), **options.merge(polymorphic: 
true)
       define_delegated_type_methods role, types: types, options: options
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/future_result.rb 
new/lib/active_record/future_result.rb
--- old/lib/active_record/future_result.rb      2024-12-13 21:02:34.000000000 
+0100
+++ new/lib/active_record/future_result.rb      1980-01-02 01:00:00.000000000 
+0100
@@ -108,9 +108,9 @@
           begin
             if pending?
               @event_buffer = EventBuffer.new(self, @instrumenter)
-              connection.with_instrumenter(@event_buffer) do
-                execute_query(connection, async: true)
-              end
+              
ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] = 
@event_buffer
+
+              execute_query(connection, async: true)
             end
           ensure
             @mutex.unlock
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/gem_version.rb 
new/lib/active_record/gem_version.rb
--- old/lib/active_record/gem_version.rb        2024-12-13 21:02:34.000000000 
+0100
+++ new/lib/active_record/gem_version.rb        1980-01-02 01:00:00.000000000 
+0100
@@ -9,8 +9,8 @@
   module VERSION
     MAJOR = 8
     MINOR = 0
-    TINY  = 1
-    PRE   = nil
+    TINY  = 2
+    PRE   = "1"
 
     STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
   end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/migration/command_recorder.rb 
new/lib/active_record/migration/command_recorder.rb
--- old/lib/active_record/migration/command_recorder.rb 2024-12-13 
21:02:34.000000000 +0100
+++ new/lib/active_record/migration/command_recorder.rb 1980-01-02 
01:00:00.000000000 +0100
@@ -213,7 +213,9 @@
             raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, 
drop_table is only reversible if given options or a block (can be empty)."
           end
 
-          super(args.push(options), &block)
+          args << options unless options.empty?
+
+          super(args, &block)
         end
 
         def invert_rename_table(args)
@@ -380,7 +382,8 @@
             raise ActiveRecord::IrreversibleMigration, "rename_enum_value is 
only reversible if given a :from and :to option."
           end
 
-          [:rename_enum_value, [type_name, from: options[:to], to: 
options[:from]]]
+          options[:to], options[:from] = options[:from], options[:to]
+          [:rename_enum_value, [type_name, options]]
         end
 
         def invert_drop_virtual_table(args)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/railties/databases.rake 
new/lib/active_record/railties/databases.rake
--- old/lib/active_record/railties/databases.rake       2024-12-13 
21:02:34.000000000 +0100
+++ new/lib/active_record/railties/databases.rake       1980-01-02 
01:00:00.000000000 +0100
@@ -160,7 +160,7 @@
       end
     end
 
-    # desc 'Resets your database using your migrations for the current 
environment'
+    desc "Resets your database using your migrations for the current 
environment"
     task reset: ["db:drop", "db:create", "db:schema:dump", "db:migrate"]
 
     desc 'Run the "up" for a given migration VERSION.'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/relation/calculations.rb 
new/lib/active_record/relation/calculations.rb
--- old/lib/active_record/relation/calculations.rb      2024-12-13 
21:02:34.000000000 +0100
+++ new/lib/active_record/relation/calculations.rb      1980-01-02 
01:00:00.000000000 +0100
@@ -410,6 +410,18 @@
       async.ids
     end
 
+    protected
+      def aggregate_column(column_name)
+        case column_name
+        when Arel::Expressions
+          column_name
+        when :all
+          Arel.star
+        else
+          arel_column(column_name)
+        end
+      end
+
     private
       def all_attributes?(column_names)
         (column_names.map(&:to_s) - model.attribute_names - 
model.attribute_aliases.keys).empty?
@@ -450,17 +462,6 @@
         column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
       end
 
-      def aggregate_column(column_name)
-        case column_name
-        when Arel::Expressions
-          column_name
-        when :all
-          Arel.star
-        else
-          arel_column(column_name)
-        end
-      end
-
       def operation_over_aggregate_column(column, operation, distinct)
         operation == "count" ? column.count(distinct) : 
column.public_send(operation)
       end
@@ -476,7 +477,7 @@
           # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
           relation = unscope(:order).distinct!(false)
 
-          column = aggregate_column(column_name)
+          column = relation.aggregate_column(column_name)
           select_value = operation_over_aggregate_column(column, operation, 
distinct)
           select_value.distinct = true if operation == "sum" && distinct
 
@@ -486,7 +487,11 @@
         end
 
         query_result = if relation.where_clause.contradiction?
-          ActiveRecord::Result.empty
+          if @async
+            FutureResult.wrap(ActiveRecord::Result.empty)
+          else
+            ActiveRecord::Result.empty
+          end
         else
           skip_query_cache_if_necessary do
             model.with_connection do |c|
@@ -515,7 +520,9 @@
           associated   = association && association.belongs_to? # only count 
belongs_to associations
           group_fields = Array(association.foreign_key) if associated
         end
-        group_fields = arel_columns(group_fields)
+
+        relation = except(:group).distinct!(false)
+        group_fields = relation.arel_columns(group_fields)
 
         model.with_connection do |connection|
           column_alias_tracker = ColumnAliasTracker.new(connection)
@@ -526,7 +533,7 @@
           }
           group_columns = group_aliases.zip(group_fields)
 
-          column = aggregate_column(column_name)
+          column = relation.aggregate_column(column_name)
           column_alias = column_alias_tracker.alias_for("#{operation} 
#{column_name.to_s.downcase}")
           select_value = operation_over_aggregate_column(column, operation, 
distinct)
           select_value.as(model.adapter_class.quote_column_name(column_alias))
@@ -543,7 +550,6 @@
             end
           }
 
-          relation = except(:group).distinct!(false)
           relation.group_values  = group_fields
           relation.select_values = select_values
 
@@ -659,7 +665,7 @@
           relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] 
unless distinct
         else
           column_alias = Arel.sql("count_column")
-          relation.select_values = [ 
aggregate_column(column_name).as(column_alias) ]
+          relation.select_values = [ 
relation.aggregate_column(column_name).as(column_alias) ]
         end
 
         subquery_alias = Arel.sql("subquery_for_count", retryable: true)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/relation/finder_methods.rb 
new/lib/active_record/relation/finder_methods.rb
--- old/lib/active_record/relation/finder_methods.rb    2024-12-13 
21:02:34.000000000 +0100
+++ new/lib/active_record/relation/finder_methods.rb    1980-01-02 
01:00:00.000000000 +0100
@@ -424,12 +424,13 @@
         error << " with#{conditions}" if conditions
         raise RecordNotFound.new(error, name, key)
       elsif Array.wrap(ids).size == 1
-        error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
+        id = Array.wrap(ids)[0]
+        error = "Couldn't find #{name} with 
'#{key}'=#{id.inspect}#{conditions}"
         raise RecordNotFound.new(error, name, key, ids)
       else
         error = +"Couldn't find all #{name.pluralize} with '#{key}': "
-        error << "(#{ids.join(", ")})#{conditions} (found #{result_size} 
results, but was looking for #{expected_size})."
-        error << " Couldn't find #{name.pluralize(not_found_ids.size)} with 
#{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if 
not_found_ids
+        error << "(#{ids.map(&:inspect).join(", ")})#{conditions} (found 
#{result_size} results, but was looking for #{expected_size})."
+        error << " Couldn't find #{name.pluralize(not_found_ids.size)} with 
#{key.to_s.pluralize(not_found_ids.size)} 
#{not_found_ids.map(&:inspect).join(', ')}." if not_found_ids
         raise RecordNotFound.new(error, name, key, ids)
       end
     end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/relation.rb 
new/lib/active_record/relation.rb
--- old/lib/active_record/relation.rb   2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/relation.rb   1980-01-02 01:00:00.000000000 +0100
@@ -820,7 +820,7 @@
     #
     # [:returning]
     #   (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to 
return for all successfully
-    #   inserted records, which by default is the primary key.
+    #   upserted records, which by default is the primary key.
     #   Pass <tt>returning: %w[ id name ]</tt> for both id and name
     #   or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> 
SQL
     #   clause entirely.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/signed_id.rb 
new/lib/active_record/signed_id.rb
--- old/lib/active_record/signed_id.rb  2024-12-13 21:02:34.000000000 +0100
+++ new/lib/active_record/signed_id.rb  1980-01-02 01:00:00.000000000 +0100
@@ -76,8 +76,9 @@
       end
 
       # The verifier instance that all signed ids are generated and verified 
from. By default, it'll be initialized
-      # with the class-level +signed_id_verifier_secret+, which within \Rails 
comes from the
-      # Rails.application.key_generator. By default, it's SHA256 for the 
digest and JSON for the serialization.
+      # with the class-level +signed_id_verifier_secret+, which within Rails 
comes from
+      # 
{Rails.application.key_generator}[rdoc-ref:Rails::Application#key_generator].
+      # By default, it's SHA256 for the digest and JSON for the serialization.
       def signed_id_verifier
         @signed_id_verifier ||= begin
           secret = signed_id_verifier_secret
@@ -93,7 +94,7 @@
 
       # Allows you to pass in a custom verifier used for the signed ids. This 
also allows you to use different
       # verifiers for different classes. This is also helpful if you need to 
rotate keys, as you can prepare
-      # your custom verifier for that in advance. See 
+ActiveSupport::MessageVerifier+ for details.
+      # your custom verifier for that in advance. See 
ActiveSupport::MessageVerifier for details.
       def signed_id_verifier=(verifier)
         @signed_id_verifier = verifier
       end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/statement_cache.rb 
new/lib/active_record/statement_cache.rb
--- old/lib/active_record/statement_cache.rb    2024-12-13 21:02:34.000000000 
+0100
+++ new/lib/active_record/statement_cache.rb    1980-01-02 01:00:00.000000000 
+0100
@@ -74,13 +74,13 @@
         self
       end
 
-      def add_bind(obj)
+      def add_bind(obj, &)
         @binds << obj
         @parts << Substitute.new
         self
       end
 
-      def add_binds(binds, proc_for_binds = nil)
+      def add_binds(binds, proc_for_binds = nil, &)
         @binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
         binds.size.times do |i|
           @parts << ", " unless i == 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_record/transactions.rb 
new/lib/active_record/transactions.rb
--- old/lib/active_record/transactions.rb       2024-12-13 21:02:34.000000000 
+0100
+++ new/lib/active_record/transactions.rb       1980-01-02 01:00:00.000000000 
+0100
@@ -219,12 +219,11 @@
     # database error will occur because the savepoint has already been
     # automatically released. The following example demonstrates the problem:
     #
-    #   Model.lease_connection.transaction do                           # BEGIN
-    #     Model.lease_connection.transaction(requires_new: true) do     # 
CREATE SAVEPOINT active_record_1
-    #       Model.lease_connection.create_table(...)                    # 
active_record_1 now automatically released
-    #     end                                                     # RELEASE 
SAVEPOINT active_record_1
-    #                                                             # ^^^^ BOOM! 
database error!
-    #   end
+    #   Model.transaction do                           # BEGIN
+    #     Model.transaction(requires_new: true) do     # CREATE SAVEPOINT 
active_record_1
+    #       Model.lease_connection.create_table(...)   # active_record_1 now 
automatically released
+    #     end                                          # RELEASE SAVEPOINT 
active_record_1
+    #   end                                            # ^^^^ BOOM! database 
error!
     #
     # Note that "TRUNCATE" is also a MySQL DDL statement!
     module ClassMethods
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/arel/collectors/bind.rb 
new/lib/arel/collectors/bind.rb
--- old/lib/arel/collectors/bind.rb     2024-12-13 21:02:34.000000000 +0100
+++ new/lib/arel/collectors/bind.rb     1980-01-02 01:00:00.000000000 +0100
@@ -18,7 +18,7 @@
         self
       end
 
-      def add_binds(binds, proc_for_binds = nil)
+      def add_binds(binds, proc_for_binds = nil, &)
         @binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
         self
       end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/arel/collectors/sql_string.rb 
new/lib/arel/collectors/sql_string.rb
--- old/lib/arel/collectors/sql_string.rb       2024-12-13 21:02:34.000000000 
+0100
+++ new/lib/arel/collectors/sql_string.rb       1980-01-02 01:00:00.000000000 
+0100
@@ -12,7 +12,7 @@
         @bind_index = 1
       end
 
-      def add_bind(bind)
+      def add_bind(bind, &)
         self << yield(@bind_index)
         @bind_index += 1
         self
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/arel/collectors/substitute_binds.rb 
new/lib/arel/collectors/substitute_binds.rb
--- old/lib/arel/collectors/substitute_binds.rb 2024-12-13 21:02:34.000000000 
+0100
+++ new/lib/arel/collectors/substitute_binds.rb 1980-01-02 01:00:00.000000000 
+0100
@@ -15,12 +15,12 @@
         self
       end
 
-      def add_bind(bind)
+      def add_bind(bind, &)
         bind = bind.value_for_database if bind.respond_to?(:value_for_database)
         self << quoter.quote(bind)
       end
 
-      def add_binds(binds, proc_for_binds = nil)
+      def add_binds(binds, proc_for_binds = nil, &)
         self << binds.map { |bind| quoter.quote(bind) }.join(", ")
       end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/arel/nodes/binary.rb new/lib/arel/nodes/binary.rb
--- old/lib/arel/nodes/binary.rb        2024-12-13 21:02:34.000000000 +0100
+++ new/lib/arel/nodes/binary.rb        1980-01-02 01:00:00.000000000 +0100
@@ -30,7 +30,7 @@
     end
 
     module FetchAttribute
-      def fetch_attribute
+      def fetch_attribute(&)
         if left.is_a?(Arel::Attributes::Attribute)
           yield left
         elsif right.is_a?(Arel::Attributes::Attribute)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/arel/nodes/node.rb new/lib/arel/nodes/node.rb
--- old/lib/arel/nodes/node.rb  2024-12-13 21:02:34.000000000 +0100
+++ new/lib/arel/nodes/node.rb  1980-01-02 01:00:00.000000000 +0100
@@ -152,7 +152,7 @@
         end
       end
 
-      def fetch_attribute
+      def fetch_attribute(&)
       end
 
       def equality?; false; end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/arel/nodes/sql_literal.rb 
new/lib/arel/nodes/sql_literal.rb
--- old/lib/arel/nodes/sql_literal.rb   2024-12-13 21:02:34.000000000 +0100
+++ new/lib/arel/nodes/sql_literal.rb   1980-01-02 01:00:00.000000000 +0100
@@ -19,7 +19,7 @@
         coder.scalar = self.to_s
       end
 
-      def fetch_attribute
+      def fetch_attribute(&)
       end
 
       def +(other)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/arel/visitors/to_sql.rb 
new/lib/arel/visitors/to_sql.rb
--- old/lib/arel/visitors/to_sql.rb     2024-12-13 21:02:34.000000000 +0100
+++ new/lib/arel/visitors/to_sql.rb     1980-01-02 01:00:00.000000000 +0100
@@ -763,7 +763,7 @@
 
         def visit_Arel_Nodes_SqlLiteral(o, collector)
           collector.preparable = false
-          collector.retryable = o.retryable
+          collector.retryable &&= o.retryable
           collector << o.to_s
         end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2024-12-13 21:02:34.000000000 +0100
+++ new/metadata        1980-01-02 01:00:00.000000000 +0100
@@ -1,14 +1,13 @@
 --- !ruby/object:Gem::Specification
 name: activerecord
 version: !ruby/object:Gem::Version
-  version: 8.0.1
+  version: 8.0.2.1
 platform: ruby
 authors:
 - David Heinemeier Hansson
-autorequire: 
 bindir: bin
 cert_chain: []
-date: 2024-12-13 00:00:00.000000000 Z
+date: 1980-01-02 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: activesupport
@@ -16,28 +15,28 @@
     requirements:
     - - '='
       - !ruby/object:Gem::Version
-        version: 8.0.1
+        version: 8.0.2.1
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
     requirements:
     - - '='
       - !ruby/object:Gem::Version
-        version: 8.0.1
+        version: 8.0.2.1
 - !ruby/object:Gem::Dependency
   name: activemodel
   requirement: !ruby/object:Gem::Requirement
     requirements:
     - - '='
       - !ruby/object:Gem::Version
-        version: 8.0.1
+        version: 8.0.2.1
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
     requirements:
     - - '='
       - !ruby/object:Gem::Version
-        version: 8.0.1
+        version: 8.0.2.1
 - !ruby/object:Gem::Dependency
   name: timeout
   requirement: !ruby/object:Gem::Requirement
@@ -475,12 +474,11 @@
 - MIT
 metadata:
   bug_tracker_uri: https://github.com/rails/rails/issues
-  changelog_uri: 
https://github.com/rails/rails/blob/v8.0.1/activerecord/CHANGELOG.md
-  documentation_uri: https://api.rubyonrails.org/v8.0.1/
+  changelog_uri: 
https://github.com/rails/rails/blob/v8.0.2.1/activerecord/CHANGELOG.md
+  documentation_uri: https://api.rubyonrails.org/v8.0.2.1/
   mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
-  source_code_uri: https://github.com/rails/rails/tree/v8.0.1/activerecord
+  source_code_uri: https://github.com/rails/rails/tree/v8.0.2.1/activerecord
   rubygems_mfa_required: 'true'
-post_install_message: 
 rdoc_options:
 - "--main"
 - README.rdoc
@@ -497,8 +495,7 @@
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
-rubygems_version: 3.5.22
-signing_key: 
+rubygems_version: 3.6.9
 specification_version: 4
 summary: Object-relational mapper framework (part of Rails).
 test_files: []

Reply via email to