🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

activerecord

Package Overview
Dependencies
Maintainers
1
Versions
519
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

activerecord - rubygems Package Compare versions

Comparing version
8.1.1
to
8.1.2
+70
-0
CHANGELOG.md

@@ -0,1 +1,71 @@

## Rails 8.1.2 (January 08, 2026) ##
* Fix counting cached queries in `ActiveRecord::RuntimeRegistry`.
*fatkodima*
* Fix merging relations with arel equality predicates with null relations.
*fatkodima*
* Fix SQLite3 schema dump for non-autoincrement integer primary keys.
Previously, `schema.rb` should incorrectly restore that table with an auto incrementing
primary key.
*Chris Hasiński*
* Fix PostgreSQL `schema_search_path` not being reapplied after `reset!` or `reconnect!`.
The `schema_search_path` configured in `database.yml` is now correctly
reapplied instead of falling back to PostgreSQL defaults.
*Tobias Egli*
* Restore the ability of enum to be foats.
```ruby
enum :rating, { low: 0.0, medium: 0.5, high: 1.0 },
```
In Rails 8.1.0, enum values are eagerly validated, and floats weren't expected.
*Said Kaldybaev*
* Ensure batched preloaded associations accounts for klass when grouping to avoid issues with STI.
*zzak*, *Stjepan Hadjic*
* Fix `ActiveRecord::SoleRecordExceeded#record` to return the relation.
This was the case until Rails 7.2, but starting from 8.0 it
started mistakenly returning the model class.
*Jean Boussier*
* Improve PostgreSQLAdapter resilience to Timeout.timeout.
Better handle asynchronous exceptions being thrown inside
the `reconnect!` method.
This may fixes some deep errors such as:
```
undefined method `key?' for nil:NilClass (NoMethodError)
if !type_map.key?(oid)
```
*Jean Boussier*
* Fix structured events for Active Record was not being emitted.
*Yuji Yaginuma*
* Fix `eager_load` when loading `has_many` assocations with composite primary keys.
This would result in some records being loaded multiple times.
*Martin-Alexander*
## Rails 8.1.1 (October 28, 2025) ##

@@ -2,0 +72,0 @@

+2
-2

@@ -106,3 +106,3 @@ # frozen_string_literal: true

def instantiate(result_set, strict_loading_value, &block)
primary_key = aliases.column_alias(join_root, join_root.primary_key)
primary_key = Array(join_root.primary_key).map { |column| aliases.column_alias(join_root, column) }

@@ -145,3 +145,3 @@ seen = Hash.new { |i, parent|

result_set.each { |row_hash|
parent_key = primary_key ? row_hash[primary_key] : row_hash
parent_key = primary_key.empty? ? row_hash : row_hash.values_at(*primary_key)
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, column_types, &block)

@@ -148,0 +148,0 @@ construct(parent, join_root, row_hash, seen, model_cache, strict_loading_value)

@@ -41,3 +41,9 @@ # frozen_string_literal: true

def group_and_load_similar(loaders)
loaders.grep_v(ThroughAssociation).group_by(&:loader_query).each_pair do |query, similar_loaders|
non_through = loaders.grep_v(ThroughAssociation)
grouped = non_through.group_by do |loader|
[loader.loader_query, loader.klass]
end
grouped.each do |(query, _klass), similar_loaders|
query.load_records_in_batch(similar_loaders)

@@ -44,0 +50,0 @@ end

@@ -9,2 +9,3 @@ # frozen_string_literal: true

require "active_record/log_subscriber"
require "active_record/structured_event_subscriber"
require "active_record/relation/delegation"

@@ -11,0 +12,0 @@ require "active_record/attributes"

@@ -716,33 +716,32 @@ # frozen_string_literal: true

@lock.synchronize do
@allow_preconnect = false
attempt_configure_connection do
@allow_preconnect = false
reconnect
reconnect
enable_lazy_transactions!
@raw_connection_dirty = false
@last_activity = @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@verified = true
@allow_preconnect = true
enable_lazy_transactions!
@raw_connection_dirty = false
@last_activity = @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@verified = true
@allow_preconnect = true
reset_transaction(restore: restore_transactions) do
clear_cache!(new_connection: true)
attempt_configure_connection
end
rescue => original_exception
translated_exception = translate_exception_class(original_exception, nil, nil)
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
reset_transaction(restore: restore_transactions) do
clear_cache!(new_connection: true)
configure_connection
end
rescue => original_exception
translated_exception = translate_exception_class(original_exception, nil, nil)
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
if !retry_deadline_exceeded && retries_available > 0
retries_available -= 1
if !retry_deadline_exceeded && retries_available > 0
retries_available -= 1
if retryable_connection_error?(translated_exception)
backoff(connection_retries - retries_available)
retry
if retryable_connection_error?(translated_exception)
backoff(connection_retries - retries_available)
retry
end
end
raise translated_exception
end
@last_activity = nil
@verified = false
raise translated_exception
end

@@ -759,2 +758,4 @@ end

@connected_since = nil
@last_activity = nil
@verified = false
end

@@ -782,5 +783,7 @@ end

def reset!
clear_cache!(new_connection: true)
reset_transaction
attempt_configure_connection
attempt_configure_connection do
clear_cache!(new_connection: true)
reset_transaction
configure_connection
end
end

@@ -819,8 +822,10 @@

if @unconfigured_connection
@raw_connection = @unconfigured_connection
@unconfigured_connection = nil
attempt_configure_connection
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@verified = true
@allow_preconnect = true
attempt_configure_connection do
@raw_connection = @unconfigured_connection
@unconfigured_connection = nil
configure_connection
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@verified = true
@allow_preconnect = true
end
return

@@ -1289,3 +1294,3 @@ end

def attempt_configure_connection
configure_connection
yield
rescue Exception # Need to handle things such as Timeout::ExitException

@@ -1292,0 +1297,0 @@ disconnect!

@@ -398,2 +398,7 @@ # frozen_string_literal: true

def clear_cache!(new_connection: false)
super
@schema_search_path = nil if new_connection
end
# Disconnects from the database if already connected. Otherwise, this

@@ -1013,2 +1018,4 @@ # method does nothing.

schema_search_path # populate cache
reload_type_map

@@ -1015,0 +1022,0 @@ end

@@ -22,9 +22,21 @@ # frozen_string_literal: true

def default_primary_key?(column)
schema_type(column) == :integer
schema_type(column) == :integer && primary_key_has_autoincrement?
end
def explicit_primary_key_default?(column)
column.bigint?
column.bigint? || (column.type == :integer && !primary_key_has_autoincrement?)
end
def primary_key_has_autoincrement?
return false unless table_name
table_sql = @connection.query_value(<<~SQL, "SCHEMA")
SELECT sql FROM sqlite_master WHERE name = #{@connection.quote(table_name)} AND type = 'table'
UNION ALL
SELECT sql FROM sqlite_temp_master WHERE name = #{@connection.quote(table_name)} AND type = 'table'
SQL
table_sql.to_s.match?(/\bAUTOINCREMENT\b/i)
end
def prepare_column_options(column)

@@ -31,0 +43,0 @@ spec = super

@@ -352,6 +352,6 @@ # frozen_string_literal: true

case value
when String, Integer, true, false, nil
when String, Integer, Float, true, false, nil
# noop
else
raise ArgumentError, "Enum values #{values} must be only booleans, integers, symbols or strings, got: #{value.class}"
raise ArgumentError, "Enum values #{values} must be only booleans, integers, floats, symbols or strings, got: #{value.class}"
end

@@ -358,0 +358,0 @@ end

@@ -12,3 +12,3 @@ # frozen_string_literal: true

MINOR = 1
TINY = 1
TINY = 2
PRE = nil

@@ -15,0 +15,0 @@

@@ -1025,3 +1025,3 @@ # frozen_string_literal: true

#
# Both calls delete the affected posts all at once with a single DELETE statement.
# This call deletes the affected posts all at once with a single DELETE statement.
# If you need to destroy dependent associations or call your <tt>before_*</tt> or

@@ -1028,0 +1028,0 @@ # +after_destroy+ callbacks, use the #destroy_all method instead.

@@ -151,3 +151,3 @@ # frozen_string_literal: true

else
raise ActiveRecord::SoleRecordExceeded.new(model)
raise ActiveRecord::SoleRecordExceeded.new(self)
end

@@ -154,0 +154,0 @@ end

@@ -185,3 +185,3 @@ # frozen_string_literal: true

predicates.reject do |node|
if !non_attrs.empty? && node.equality? && node.left.is_a?(Arel::Predications)
if !non_attrs.empty? && equality_node?(node) && node.left.is_a?(Arel::Predications)
non_attrs.include?(node.left)

@@ -188,0 +188,0 @@ end || Arel.fetch_attribute(node) do |attr|

@@ -36,2 +36,3 @@ # frozen_string_literal: true

(finish - start) * 1_000.0,
cached: payload[:cached],
async: payload[:async],

@@ -38,0 +39,0 @@ lock_wait: payload[:lock_wait],

@@ -235,4 +235,4 @@ # frozen_string_literal: true

add_index_statements = indexes.map do |index|
table_name = remove_prefix_and_suffix(index.table).inspect
" add_index #{([relation_name(table_name)] + index_parts(index)).join(', ')}"
table_name = remove_prefix_and_suffix(index.table)
" add_index #{([relation_name(table_name).inspect] + index_parts(index)).join(', ')}"
end

@@ -239,0 +239,0 @@

Sorry, the diff of this file is too big to display