activerecord 8.1.2.1 → 8.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/future_result.rb +2 -0
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +2 -2
- data/lib/active_record/migration/command_recorder.rb +1 -1
- data/lib/active_record/relation/batches.rb +2 -2
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/type/json.rb +1 -3
- data/lib/active_record/type/serialized.rb +5 -0
- data/lib/active_record.rb +1 -1
- data/lib/arel/predications.rb +1 -3
- metadata +8 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf11d5e6abc99265d39fb3f4b3b0d87f1e2bbdf6099a478306ba3d04ac2a760a
|
|
4
|
+
data.tar.gz: 4d47ba93fb7a68eb7cbadf3a001bb676b71b87a06b00504907717059c39190b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bcbbfd82d1032400a7f3dfa0784bd5d506107d50d0ada3e1fefd26de665959e1f86cb2aa5f4e7cfbb24e69101e3b71542abd1ecffaa53963823ae47fa4e26475
|
|
7
|
+
data.tar.gz: ce6acb68c3c821dfda84556f5089effcf401cff05b8d819297430b77d51699bf096bc2ed69f78161f9750bd45bbe3ffaa2b591b08d6676dd437e8a9fc06952d4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,61 @@
|
|
|
1
|
+
## Rails 8.1.3 (March 24, 2026) ##
|
|
2
|
+
|
|
3
|
+
* Fix `insert_all` and `upsert_all` log message when called on anonymous classes.
|
|
4
|
+
|
|
5
|
+
*Gabriel Sobrinho*
|
|
6
|
+
|
|
7
|
+
* Respect `ActiveRecord::SchemaDumper.ignore_tables` when dumping SQLite virtual tables.
|
|
8
|
+
|
|
9
|
+
*Hans Schnedlitz*
|
|
10
|
+
|
|
11
|
+
* Restore previous instrumenter after `execute_or_skip`
|
|
12
|
+
|
|
13
|
+
`FutureResult#execute_or_skip` replaces the thread's instrumenter with an
|
|
14
|
+
`EventBuffer` to collect events published during async query execution.
|
|
15
|
+
If the global async executor is saturated and the `caller_runs` fallback
|
|
16
|
+
executes the task on the calling thread, we need to make sure the previous
|
|
17
|
+
instrumenter is restored or the stale `EventBuffer` would stay in place and
|
|
18
|
+
permanently swallow all subsequent `sql.active_record` notifications on
|
|
19
|
+
that thread.
|
|
20
|
+
|
|
21
|
+
*Rosa Gutierrez*
|
|
22
|
+
|
|
23
|
+
* Bump the minimum PostgreSQL version to 9.5, due to usage of `array_position` function.
|
|
24
|
+
|
|
25
|
+
*Ivan Kuchin*
|
|
26
|
+
|
|
27
|
+
* Fix Ruby 4.0 delegator warning when calling inspect on ActiveRecord::Type::Serialized.
|
|
28
|
+
|
|
29
|
+
*Hammad Khan*
|
|
30
|
+
|
|
31
|
+
* Fix support for table names containing hyphens.
|
|
32
|
+
|
|
33
|
+
*Evgeniy Demin*
|
|
34
|
+
|
|
35
|
+
* Fix column deduplication for SQLite3 and PostgreSQL virtual (generated) columns.
|
|
36
|
+
|
|
37
|
+
`Column#==` and `Column#hash` now account for `virtual?` so that the
|
|
38
|
+
`Deduplicable` registry does not treat a generated column and a regular
|
|
39
|
+
column with the same name and type as identical. Previously, if a
|
|
40
|
+
generated column was registered first, a regular column on a different
|
|
41
|
+
table could be deduplicated to the generated instance, silently
|
|
42
|
+
excluding it from INSERT/UPDATE statements.
|
|
43
|
+
|
|
44
|
+
*Jay Huber*
|
|
45
|
+
|
|
46
|
+
* Fix PostgreSQL schema dumping to handle schema-qualified table names in foreign_key references that span different schemas.
|
|
47
|
+
|
|
48
|
+
# before
|
|
49
|
+
add_foreign_key "hst.event_log_attributes", "hst.event_logs" # emits correctly because they're in the same schema (hst)
|
|
50
|
+
add_foreign_key "hst.event_log_attributes", "hst.usr.user_profiles", column: "created_by_id" # emits hst.user.* when user.* is expected
|
|
51
|
+
|
|
52
|
+
# after
|
|
53
|
+
add_foreign_key "hst.event_log_attributes", "hst.event_logs"
|
|
54
|
+
add_foreign_key "hst.event_log_attributes", "usr.user_profiles", column: "created_by_id"
|
|
55
|
+
|
|
56
|
+
*Chiperific*
|
|
57
|
+
|
|
58
|
+
|
|
1
59
|
## Rails 8.1.2.1 (March 23, 2026) ##
|
|
2
60
|
|
|
3
61
|
* No changes.
|
|
@@ -129,7 +129,7 @@ module ActiveRecord
|
|
|
129
129
|
class ConnectionPool
|
|
130
130
|
# Prior to 3.3.5, WeakKeyMap had a use after free bug
|
|
131
131
|
# https://bugs.ruby-lang.org/issues/20688
|
|
132
|
-
if ObjectSpace.const_defined?(:WeakKeyMap) && RUBY_VERSION >= "3.3.5"
|
|
132
|
+
if ObjectSpace.const_defined?(:WeakKeyMap) && Gem::Version.new(RUBY_VERSION) >= "3.3.5"
|
|
133
133
|
WeakThreadKeyMap = ObjectSpace::WeakKeyMap
|
|
134
134
|
else
|
|
135
135
|
class WeakThreadKeyMap # :nodoc:
|
|
@@ -526,7 +526,7 @@ module ActiveRecord
|
|
|
526
526
|
end
|
|
527
527
|
conn.disconnect!
|
|
528
528
|
end
|
|
529
|
-
@connections = []
|
|
529
|
+
@connections = @pinned_connection ? [@pinned_connection] : []
|
|
530
530
|
@leases.clear
|
|
531
531
|
@available.clear
|
|
532
532
|
|
|
@@ -753,7 +753,7 @@ module ActiveRecord
|
|
|
753
753
|
end
|
|
754
754
|
|
|
755
755
|
def extract_table_ref_from_insert_sql(sql)
|
|
756
|
-
if sql =~ /into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im
|
|
756
|
+
if sql =~ /into\s("[-A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im
|
|
757
757
|
$1.delete('"').strip
|
|
758
758
|
end
|
|
759
759
|
end
|
|
@@ -1604,11 +1604,11 @@ module ActiveRecord
|
|
|
1604
1604
|
non_combinable_operations = []
|
|
1605
1605
|
|
|
1606
1606
|
operations.each do |command, args|
|
|
1607
|
-
|
|
1607
|
+
args.shift # remove table_name
|
|
1608
1608
|
method = :"#{command}_for_alter"
|
|
1609
1609
|
|
|
1610
1610
|
if respond_to?(method, true)
|
|
1611
|
-
sqls, procs = Array(send(method,
|
|
1611
|
+
sqls, procs = Array(send(method, table_name, *args)).partition { |v| v.is_a?(String) }
|
|
1612
1612
|
sql_fragments.concat(sqls)
|
|
1613
1613
|
non_combinable_operations.concat(procs)
|
|
1614
1614
|
else
|
|
@@ -1616,7 +1616,7 @@ module ActiveRecord
|
|
|
1616
1616
|
non_combinable_operations.each(&:call)
|
|
1617
1617
|
sql_fragments = []
|
|
1618
1618
|
non_combinable_operations = []
|
|
1619
|
-
send(command,
|
|
1619
|
+
send(command, table_name, *args)
|
|
1620
1620
|
end
|
|
1621
1621
|
end
|
|
1622
1622
|
|
|
@@ -126,7 +126,7 @@ module ActiveRecord
|
|
|
126
126
|
|
|
127
127
|
# Opens a database console session.
|
|
128
128
|
def self.dbconsole(config, options = {})
|
|
129
|
-
raise NotImplementedError.new("#{self
|
|
129
|
+
raise NotImplementedError.new("#{self} should define `dbconsole` that accepts a db config and options to implement connecting to the db console")
|
|
130
130
|
end
|
|
131
131
|
|
|
132
132
|
def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
|
|
@@ -69,7 +69,8 @@ module ActiveRecord
|
|
|
69
69
|
other.is_a?(Column) &&
|
|
70
70
|
super &&
|
|
71
71
|
identity? == other.identity? &&
|
|
72
|
-
serial? == other.serial?
|
|
72
|
+
serial? == other.serial? &&
|
|
73
|
+
virtual? == other.virtual?
|
|
73
74
|
end
|
|
74
75
|
alias :eql? :==
|
|
75
76
|
|
|
@@ -77,7 +78,8 @@ module ActiveRecord
|
|
|
77
78
|
Column.hash ^
|
|
78
79
|
super.hash ^
|
|
79
80
|
identity?.hash ^
|
|
80
|
-
serial?.hash
|
|
81
|
+
serial?.hash ^
|
|
82
|
+
virtual?.hash
|
|
81
83
|
end
|
|
82
84
|
end
|
|
83
85
|
end
|
|
@@ -682,8 +682,8 @@ module ActiveRecord
|
|
|
682
682
|
end
|
|
683
683
|
|
|
684
684
|
def check_version # :nodoc:
|
|
685
|
-
if database_version <
|
|
686
|
-
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.
|
|
685
|
+
if database_version < 9_05_00 # < 9.5
|
|
686
|
+
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.5."
|
|
687
687
|
end
|
|
688
688
|
end
|
|
689
689
|
|
|
@@ -46,7 +46,9 @@ module ActiveRecord
|
|
|
46
46
|
def ==(other)
|
|
47
47
|
other.is_a?(Column) &&
|
|
48
48
|
super &&
|
|
49
|
-
auto_increment? == other.auto_increment?
|
|
49
|
+
auto_increment? == other.auto_increment? &&
|
|
50
|
+
rowid == other.rowid &&
|
|
51
|
+
generated_type == other.generated_type
|
|
50
52
|
end
|
|
51
53
|
alias :eql? :==
|
|
52
54
|
|
|
@@ -54,8 +56,12 @@ module ActiveRecord
|
|
|
54
56
|
Column.hash ^
|
|
55
57
|
super.hash ^
|
|
56
58
|
auto_increment?.hash ^
|
|
57
|
-
rowid.hash
|
|
59
|
+
rowid.hash ^
|
|
60
|
+
virtual?.hash
|
|
58
61
|
end
|
|
62
|
+
|
|
63
|
+
protected
|
|
64
|
+
attr_reader :generated_type
|
|
59
65
|
end
|
|
60
66
|
end
|
|
61
67
|
end
|
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
|
6
6
|
class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
|
|
7
7
|
private
|
|
8
8
|
def virtual_tables(stream)
|
|
9
|
-
virtual_tables = @connection.virtual_tables
|
|
9
|
+
virtual_tables = @connection.virtual_tables.reject { |name, _| ignored?(name) }
|
|
10
10
|
if virtual_tables.any?
|
|
11
11
|
stream.puts
|
|
12
12
|
stream.puts " # Virtual tables defined in this database."
|
|
@@ -319,7 +319,7 @@ module ActiveRecord
|
|
|
319
319
|
exec_query "DROP INDEX #{quote_column_name(index_name)}"
|
|
320
320
|
end
|
|
321
321
|
|
|
322
|
-
VIRTUAL_TABLE_REGEX = /USING\s+(\w+)\s*\((
|
|
322
|
+
VIRTUAL_TABLE_REGEX = /USING\s+(\w+)\s*\((.*)\)/i
|
|
323
323
|
|
|
324
324
|
# Returns a list of defined virtual tables
|
|
325
325
|
def virtual_tables
|
|
@@ -105,6 +105,7 @@ module ActiveRecord
|
|
|
105
105
|
|
|
106
106
|
@pool.with_connection do |connection|
|
|
107
107
|
return unless @mutex.try_lock
|
|
108
|
+
previous_instrumenter = ActiveSupport::IsolatedExecutionState[:active_record_instrumenter]
|
|
108
109
|
begin
|
|
109
110
|
if pending?
|
|
110
111
|
@event_buffer = EventBuffer.new(self, @instrumenter)
|
|
@@ -113,6 +114,7 @@ module ActiveRecord
|
|
|
113
114
|
execute_query(connection, async: true)
|
|
114
115
|
end
|
|
115
116
|
ensure
|
|
117
|
+
ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] = previous_instrumenter
|
|
116
118
|
@mutex.unlock
|
|
117
119
|
end
|
|
118
120
|
end
|
|
@@ -39,7 +39,7 @@ module ActiveRecord
|
|
|
39
39
|
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
|
|
40
40
|
@returning = false if @returning == []
|
|
41
41
|
|
|
42
|
-
@unique_by = find_unique_index_for(@unique_by)
|
|
42
|
+
@unique_by = find_unique_index_for(@unique_by) if @on_duplicate != :raise
|
|
43
43
|
|
|
44
44
|
configure_on_duplicate_update_logic
|
|
45
45
|
ensure_valid_options_for_connection!
|
|
@@ -48,7 +48,7 @@ module ActiveRecord
|
|
|
48
48
|
def execute
|
|
49
49
|
return ActiveRecord::Result.empty if inserts.empty?
|
|
50
50
|
|
|
51
|
-
message = +"#{model} "
|
|
51
|
+
message = +"#{model.name} "
|
|
52
52
|
message << "Bulk " if inserts.many?
|
|
53
53
|
message << (on_duplicate == :update ? "Upsert" : "Insert")
|
|
54
54
|
connection.exec_insert_all to_sql, message
|
|
@@ -142,7 +142,7 @@ module ActiveRecord
|
|
|
142
142
|
recorder.reverting = @reverting
|
|
143
143
|
yield recorder.delegate.update_table_definition(table_name, recorder)
|
|
144
144
|
commands = recorder.commands
|
|
145
|
-
@commands << [:change_table, [table_name], -> t { bulk_change_table(
|
|
145
|
+
@commands << [:change_table, [table_name], -> t { bulk_change_table(t.name, commands.reverse) }]
|
|
146
146
|
else
|
|
147
147
|
yield delegate.update_table_definition(table_name, self)
|
|
148
148
|
end
|
|
@@ -441,8 +441,8 @@ module ActiveRecord
|
|
|
441
441
|
yielded_relation.load_records(records)
|
|
442
442
|
elsif (empty_scope && use_ranges != false) || use_ranges
|
|
443
443
|
# Efficiently peak at the last value for the next batch using offset and limit.
|
|
444
|
-
values_size = batch_limit
|
|
445
|
-
values_last = batch_relation.offset(
|
|
444
|
+
values_size = remaining ? [batch_limit, remaining].min : batch_limit
|
|
445
|
+
values_last = batch_relation.offset(values_size - 1).pick(*cursor)
|
|
446
446
|
|
|
447
447
|
# If the last value is not found using offset, there is at most one more batch of size < batch_limit.
|
|
448
448
|
# Retry by getting the whole list of remaining values so that we have the exact size and last value.
|
|
@@ -31,7 +31,9 @@ module ActiveRecord
|
|
|
31
31
|
values_predicate
|
|
32
32
|
else
|
|
33
33
|
array_predicates = ranges.map! { |range| predicate_builder.build(attribute, range) }
|
|
34
|
-
|
|
34
|
+
values_predicate.or(
|
|
35
|
+
Arel::Nodes::Grouping.new Arel::Nodes::Or.new(array_predicates)
|
|
36
|
+
)
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
39
|
|
|
@@ -25,10 +25,8 @@ module ActiveRecord
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
JSON_ENCODER = ActiveSupport::JSON::Encoding.json_encoder.new(escape: false)
|
|
29
|
-
|
|
30
28
|
def serialize(value)
|
|
31
|
-
|
|
29
|
+
ActiveSupport::JSON::Encoding.encode_without_escape(value) unless value.nil?
|
|
32
30
|
end
|
|
33
31
|
|
|
34
32
|
def changed_in_place?(raw_old_value, new_value)
|
|
@@ -65,6 +65,11 @@ module ActiveRecord
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
private
|
|
68
|
+
# Prevent Ruby 4.0 "delegator does not forward private method" warning.
|
|
69
|
+
# Kernel#inspect calls instance_variables_to_inspect which, without this,
|
|
70
|
+
# triggers Delegator#respond_to_missing? for a private method.
|
|
71
|
+
define_method(:instance_variables_to_inspect, Kernel.instance_method(:instance_variables))
|
|
72
|
+
|
|
68
73
|
def default_value?(value)
|
|
69
74
|
value == coder.load(nil)
|
|
70
75
|
end
|
data/lib/active_record.rb
CHANGED
|
@@ -358,7 +358,7 @@ module ActiveRecord
|
|
|
358
358
|
self.run_after_transaction_callbacks_in_order_defined = false
|
|
359
359
|
|
|
360
360
|
singleton_class.attr_accessor :raise_on_missing_required_finder_order_columns
|
|
361
|
-
self.
|
|
361
|
+
self.raise_on_missing_required_finder_order_columns = false
|
|
362
362
|
|
|
363
363
|
singleton_class.attr_accessor :application_record_class
|
|
364
364
|
self.application_record_class = nil
|
data/lib/arel/predications.rb
CHANGED
|
@@ -231,9 +231,7 @@ module Arel # :nodoc: all
|
|
|
231
231
|
private
|
|
232
232
|
def grouping_any(method_id, others, *extras)
|
|
233
233
|
nodes = others.map { |expr| send(method_id, expr, *extras) }
|
|
234
|
-
Nodes::Grouping.new nodes
|
|
235
|
-
Nodes::Or.new([memo, node])
|
|
236
|
-
}
|
|
234
|
+
Nodes::Grouping.new Nodes::Or.new(nodes)
|
|
237
235
|
end
|
|
238
236
|
|
|
239
237
|
def grouping_all(method_id, others, *extras)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.1.
|
|
4
|
+
version: 8.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Heinemeier Hansson
|
|
@@ -15,28 +15,28 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 8.1.
|
|
18
|
+
version: 8.1.3
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 8.1.
|
|
25
|
+
version: 8.1.3
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: activemodel
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - '='
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 8.1.
|
|
32
|
+
version: 8.1.3
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - '='
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 8.1.
|
|
39
|
+
version: 8.1.3
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: timeout
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -478,10 +478,10 @@ licenses:
|
|
|
478
478
|
- MIT
|
|
479
479
|
metadata:
|
|
480
480
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
|
481
|
-
changelog_uri: https://github.com/rails/rails/blob/v8.1.
|
|
482
|
-
documentation_uri: https://api.rubyonrails.org/v8.1.
|
|
481
|
+
changelog_uri: https://github.com/rails/rails/blob/v8.1.3/activerecord/CHANGELOG.md
|
|
482
|
+
documentation_uri: https://api.rubyonrails.org/v8.1.3/
|
|
483
483
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
|
484
|
-
source_code_uri: https://github.com/rails/rails/tree/v8.1.
|
|
484
|
+
source_code_uri: https://github.com/rails/rails/tree/v8.1.3/activerecord
|
|
485
485
|
rubygems_mfa_required: 'true'
|
|
486
486
|
rdoc_options:
|
|
487
487
|
- "--main"
|