activerecord 7.2.0.beta3 → 7.2.0.rc1
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 +17 -0
- data/lib/active_record/associations/association.rb +6 -0
- data/lib/active_record/associations/collection_association.rb +4 -0
- data/lib/active_record/associations/nested_error.rb +1 -1
- data/lib/active_record/associations.rb +2 -2
- data/lib/active_record/autosave_association.rb +3 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +5 -10
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +28 -10
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +3 -9
- data/lib/active_record/errors.rb +13 -4
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/relation/batches.rb +7 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -3
- data/lib/active_record/relation/query_methods.rb +4 -4
- data/lib/active_record/tasks/database_tasks.rb +19 -8
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e66951e81d8026bf99151e2232bd66141817a39c499a94f6fd00a7238514135e
|
4
|
+
data.tar.gz: 765f9e290a5a1b2a99062ac2d333bea4b5aa7a7817b19f3efb4f90745c00295b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6484ebe413014457c436ecf1cd7162acfd0d5915d4a976bbedc690be225f4061861b49898012d1d4fb372d4c07fd7aca655043958aa553e5add8ef6d84bf2994
|
7
|
+
data.tar.gz: f795c8dfe5aaea82a264d718d6e8bd3fa9ffd4f93353c766651026eeda903293b80b345ef95f18ce18ac61ba0517f69b9234ff24692cee2b0ce71affdc8a9202
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## Rails 7.2.0.rc1 (August 06, 2024) ##
|
2
|
+
|
3
|
+
* Handle commas in Sqlite3 default function definitions.
|
4
|
+
|
5
|
+
*Stephen Margheim*
|
6
|
+
|
7
|
+
* Fixes `validates_associated` raising an exception when configured with a
|
8
|
+
singular association and having `index_nested_attribute_errors` enabled.
|
9
|
+
|
10
|
+
*Martin Spickermann*
|
11
|
+
|
12
|
+
* The constant `ActiveRecord::ImmutableRelation` has been deprecated because
|
13
|
+
we want to reserve that name for a stronger sense of "immutable relation".
|
14
|
+
Please use `ActiveRecord::UnmodifiableRelation` instead.
|
15
|
+
|
16
|
+
*Xavier Noria*
|
17
|
+
|
1
18
|
## Rails 7.2.0.beta3 (July 11, 2024) ##
|
2
19
|
|
3
20
|
* Add condensed `#inspect` for `ConnectionPool`, `AbstractAdapter`, and
|
@@ -210,6 +210,12 @@ module ActiveRecord
|
|
210
210
|
_create_record(attributes, true, &block)
|
211
211
|
end
|
212
212
|
|
213
|
+
# Whether the association represent a single record
|
214
|
+
# or a collection of records.
|
215
|
+
def collection?
|
216
|
+
false
|
217
|
+
end
|
218
|
+
|
213
219
|
private
|
214
220
|
# Reader and writer methods call this so that consistent errors are presented
|
215
221
|
# when the association target class does not exist.
|
@@ -18,7 +18,7 @@ module ActiveRecord
|
|
18
18
|
def compute_attribute(inner_error)
|
19
19
|
association_name = association.reflection.name
|
20
20
|
|
21
|
-
if index_errors_setting && index
|
21
|
+
if association.collection? && index_errors_setting && index
|
22
22
|
"#{association_name}[#{index}].#{inner_error.attribute}".to_sym
|
23
23
|
else
|
24
24
|
"#{association_name}.#{inner_error.attribute}".to_sym
|
@@ -1244,9 +1244,9 @@ module ActiveRecord
|
|
1244
1244
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
1245
1245
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
1246
1246
|
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
1247
|
-
# [
|
1247
|
+
# [+:index_errors+]
|
1248
1248
|
# Allows differentiation of multiple validation errors from the association records, by including
|
1249
|
-
# an index in the error attribute name, e.g.
|
1249
|
+
# an index in the error attribute name, e.g. +roles[2].level+.
|
1250
1250
|
# When set to +true+, the index is based on association order, i.e. database order, with yet to be
|
1251
1251
|
# persisted new records placed at the end.
|
1252
1252
|
# When set to +:nested_attributes_order+, the index is based on the record order received by
|
@@ -428,7 +428,9 @@ module ActiveRecord
|
|
428
428
|
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
|
429
429
|
def save_has_one_association(reflection)
|
430
430
|
association = association_instance_get(reflection.name)
|
431
|
-
|
431
|
+
return unless association && association.loaded?
|
432
|
+
|
433
|
+
record = association.load_target
|
432
434
|
|
433
435
|
if record && !record.destroyed?
|
434
436
|
autosave = reflection.options[:autosave]
|
@@ -6,16 +6,11 @@ module ActiveRecord
|
|
6
6
|
module DatabaseStatements
|
7
7
|
# Returns an ActiveRecord::Result instance.
|
8
8
|
def select_all(*, **) # :nodoc:
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
else
|
14
|
-
super
|
15
|
-
end
|
16
|
-
conn.abandon_results!
|
9
|
+
if ExplainRegistry.collect? && prepared_statements
|
10
|
+
unprepared_statement { super }
|
11
|
+
else
|
12
|
+
super
|
17
13
|
end
|
18
|
-
result
|
19
14
|
end
|
20
15
|
|
21
16
|
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
|
@@ -60,7 +55,6 @@ module ActiveRecord
|
|
60
55
|
combine_multi_statements(statements).each do |statement|
|
61
56
|
with_raw_connection do |conn|
|
62
57
|
raw_execute(statement, name)
|
63
|
-
conn.abandon_results!
|
64
58
|
end
|
65
59
|
end
|
66
60
|
end
|
@@ -102,6 +96,7 @@ module ActiveRecord
|
|
102
96
|
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
103
97
|
sync_timezone_changes(conn)
|
104
98
|
result = conn.query(sql)
|
99
|
+
conn.abandon_results!
|
105
100
|
verified!
|
106
101
|
handle_warnings(sql)
|
107
102
|
notification_payload[:row_count] = result&.size || 0
|
@@ -472,11 +472,7 @@ module ActiveRecord
|
|
472
472
|
end
|
473
473
|
|
474
474
|
def table_structure(table_name)
|
475
|
-
structure =
|
476
|
-
internal_exec_query("PRAGMA table_xinfo(#{quote_table_name(table_name)})", "SCHEMA")
|
477
|
-
else
|
478
|
-
internal_exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
479
|
-
end
|
475
|
+
structure = table_info(table_name)
|
480
476
|
raise ActiveRecord::StatementInvalid.new("Could not find table '#{table_name}'", connection_pool: @pool) if structure.empty?
|
481
477
|
table_structure_with_collation(table_name, structure)
|
482
478
|
end
|
@@ -679,7 +675,7 @@ module ActiveRecord
|
|
679
675
|
auto_increments = {}
|
680
676
|
generated_columns = {}
|
681
677
|
|
682
|
-
column_strings = table_structure_sql(table_name)
|
678
|
+
column_strings = table_structure_sql(table_name, basic_structure.map { |column| column["name"] })
|
683
679
|
|
684
680
|
if column_strings.any?
|
685
681
|
column_strings.each do |column_string|
|
@@ -712,7 +708,15 @@ module ActiveRecord
|
|
712
708
|
end
|
713
709
|
end
|
714
710
|
|
715
|
-
|
711
|
+
UNQUOTED_OPEN_PARENS_REGEX = /\((?![^'"]*['"][^'"]*$)/
|
712
|
+
FINAL_CLOSE_PARENS_REGEX = /\);*\z/
|
713
|
+
|
714
|
+
def table_structure_sql(table_name, column_names = nil)
|
715
|
+
unless column_names
|
716
|
+
column_info = table_info(table_name)
|
717
|
+
column_names = column_info.map { |column| column["name"] }
|
718
|
+
end
|
719
|
+
|
716
720
|
sql = <<~SQL
|
717
721
|
SELECT sql FROM
|
718
722
|
(SELECT * FROM sqlite_master UNION ALL
|
@@ -722,16 +726,30 @@ module ActiveRecord
|
|
722
726
|
|
723
727
|
# Result will have following sample string
|
724
728
|
# CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
725
|
-
# "password_digest" varchar COLLATE "NOCASE"
|
729
|
+
# "password_digest" varchar COLLATE "NOCASE",
|
730
|
+
# "o_id" integer,
|
731
|
+
# CONSTRAINT "fk_rails_78146ddd2e" FOREIGN KEY ("o_id") REFERENCES "os" ("id"));
|
726
732
|
result = query_value(sql, "SCHEMA")
|
727
733
|
|
728
734
|
return [] unless result
|
729
735
|
|
730
736
|
# Splitting with left parentheses and discarding the first part will return all
|
731
737
|
# columns separated with comma(,).
|
732
|
-
|
738
|
+
result.partition(UNQUOTED_OPEN_PARENS_REGEX)
|
739
|
+
.last
|
740
|
+
.sub(FINAL_CLOSE_PARENS_REGEX, "")
|
741
|
+
# column definitions can have a comma in them, so split on commas followed
|
742
|
+
# by a space and a column name in quotes or followed by the keyword CONSTRAINT
|
743
|
+
.split(/,(?=\s(?:CONSTRAINT|"(?:#{Regexp.union(column_names).source})"))/i)
|
744
|
+
.map(&:strip)
|
745
|
+
end
|
733
746
|
|
734
|
-
|
747
|
+
def table_info(table_name)
|
748
|
+
if supports_virtual_columns?
|
749
|
+
internal_exec_query("PRAGMA table_xinfo(#{quote_table_name(table_name)})", "SCHEMA")
|
750
|
+
else
|
751
|
+
internal_exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
752
|
+
end
|
735
753
|
end
|
736
754
|
|
737
755
|
def arel_visitor
|
@@ -4,14 +4,6 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module Trilogy
|
6
6
|
module DatabaseStatements
|
7
|
-
def select_all(*, **) # :nodoc:
|
8
|
-
result = super
|
9
|
-
with_raw_connection do |conn|
|
10
|
-
conn.next_result while conn.more_results_exist?
|
11
|
-
end
|
12
|
-
result
|
13
|
-
end
|
14
|
-
|
15
7
|
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
|
16
8
|
sql = transform_query(sql)
|
17
9
|
check_if_write_query(sql)
|
@@ -47,6 +39,9 @@ module ActiveRecord
|
|
47
39
|
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
48
40
|
sync_timezone_changes(conn)
|
49
41
|
result = conn.query(sql)
|
42
|
+
while conn.more_results_exist?
|
43
|
+
conn.next_result
|
44
|
+
end
|
50
45
|
verified!
|
51
46
|
handle_warnings(sql)
|
52
47
|
notification_payload[:row_count] = result.count
|
@@ -77,7 +72,6 @@ module ActiveRecord
|
|
77
72
|
combine_multi_statements(statements).each do |statement|
|
78
73
|
with_raw_connection do |conn|
|
79
74
|
raw_execute(statement, name)
|
80
|
-
conn.next_result while conn.more_results_exist?
|
81
75
|
end
|
82
76
|
end
|
83
77
|
end
|
data/lib/active_record/errors.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/deprecation"
|
4
|
+
|
3
5
|
module ActiveRecord
|
6
|
+
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
7
|
+
|
4
8
|
# = Active Record Errors
|
5
9
|
#
|
6
10
|
# Generic Active Record exception class.
|
@@ -476,10 +480,15 @@ module ActiveRecord
|
|
476
480
|
# relation.loaded? # => true
|
477
481
|
#
|
478
482
|
# # Methods which try to mutate a loaded relation fail.
|
479
|
-
# relation.where!(title: 'TODO') # => ActiveRecord::
|
480
|
-
# relation.limit!(5) # => ActiveRecord::
|
481
|
-
class
|
482
|
-
end
|
483
|
+
# relation.where!(title: 'TODO') # => ActiveRecord::UnmodifiableRelation
|
484
|
+
# relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
|
485
|
+
class UnmodifiableRelation < ActiveRecordError
|
486
|
+
end
|
487
|
+
deprecate_constant(
|
488
|
+
:ImmutableRelation,
|
489
|
+
"ActiveRecord::UnmodifiableRelation",
|
490
|
+
deprecator: ActiveRecord.deprecator
|
491
|
+
)
|
483
492
|
|
484
493
|
# TransactionIsolationError will be raised under the following conditions:
|
485
494
|
#
|
@@ -341,7 +341,13 @@ module ActiveRecord
|
|
341
341
|
|
342
342
|
if start || finish
|
343
343
|
records = records.filter do |record|
|
344
|
-
|
344
|
+
id = record.id
|
345
|
+
|
346
|
+
if order == :asc
|
347
|
+
(start.nil? || id >= start) && (finish.nil? || id <= finish)
|
348
|
+
else
|
349
|
+
(start.nil? || id <= start) && (finish.nil? || id >= finish)
|
350
|
+
end
|
345
351
|
end
|
346
352
|
end
|
347
353
|
|
@@ -57,9 +57,15 @@ module ActiveRecord
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def convert_to_id(value)
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
if primary_key.is_a?(Array)
|
61
|
+
primary_key.map do |attribute|
|
62
|
+
if attribute == "id"
|
63
|
+
value.id_value
|
64
|
+
else
|
65
|
+
value.public_send(attribute)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
elsif value.respond_to?(primary_key)
|
63
69
|
value.public_send(primary_key)
|
64
70
|
else
|
65
71
|
value
|
@@ -173,7 +173,7 @@ module ActiveRecord
|
|
173
173
|
end # end
|
174
174
|
|
175
175
|
def #{method_name}=(value) # def includes_values=(value)
|
176
|
-
|
176
|
+
assert_modifiable! # assert_modifiable!
|
177
177
|
@values[:#{name}] = value # @values[:includes] = value
|
178
178
|
end # end
|
179
179
|
CODE
|
@@ -796,7 +796,7 @@ module ActiveRecord
|
|
796
796
|
if !VALID_UNSCOPING_VALUES.include?(scope)
|
797
797
|
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
798
798
|
end
|
799
|
-
|
799
|
+
assert_modifiable!
|
800
800
|
@values.delete(scope)
|
801
801
|
when Hash
|
802
802
|
scope.each do |key, target_value|
|
@@ -1705,8 +1705,8 @@ module ActiveRecord
|
|
1705
1705
|
)
|
1706
1706
|
end
|
1707
1707
|
|
1708
|
-
def
|
1709
|
-
raise
|
1708
|
+
def assert_modifiable!
|
1709
|
+
raise UnmodifiableRelation if @loaded || @arel
|
1710
1710
|
end
|
1711
1711
|
|
1712
1712
|
def build_arel(connection, aliases = nil)
|
@@ -192,9 +192,17 @@ module ActiveRecord
|
|
192
192
|
|
193
193
|
seed = true
|
194
194
|
end
|
195
|
+
end
|
196
|
+
end
|
195
197
|
|
196
|
-
|
197
|
-
|
198
|
+
each_current_environment(env) do |environment|
|
199
|
+
db_configs_with_versions(environment).sort.each do |version, db_configs|
|
200
|
+
db_configs.each do |db_config|
|
201
|
+
with_temporary_pool(db_config) do
|
202
|
+
migrate(version)
|
203
|
+
dump_schema(db_config) if ActiveRecord.dump_schema_after_migration
|
204
|
+
end
|
205
|
+
end
|
198
206
|
end
|
199
207
|
end
|
200
208
|
|
@@ -255,10 +263,10 @@ module ActiveRecord
|
|
255
263
|
Migration.verbose = verbose_was
|
256
264
|
end
|
257
265
|
|
258
|
-
def db_configs_with_versions # :nodoc:
|
266
|
+
def db_configs_with_versions(environment = env) # :nodoc:
|
259
267
|
db_configs_with_versions = Hash.new { |h, k| h[k] = [] }
|
260
268
|
|
261
|
-
with_temporary_pool_for_each do |pool|
|
269
|
+
with_temporary_pool_for_each(env: environment) do |pool|
|
262
270
|
db_config = pool.db_config
|
263
271
|
versions_to_run = pool.migration_context.pending_migration_versions
|
264
272
|
target_version = ActiveRecord::Tasks::DatabaseTasks.target_version
|
@@ -580,10 +588,7 @@ module ActiveRecord
|
|
580
588
|
end
|
581
589
|
|
582
590
|
def each_current_configuration(environment, name = nil)
|
583
|
-
|
584
|
-
environments << "test" if environment == "development" && !ENV["SKIP_TEST_DATABASE"] && !ENV["DATABASE_URL"]
|
585
|
-
|
586
|
-
environments.each do |env|
|
591
|
+
each_current_environment(environment) do |env|
|
587
592
|
configs_for(env_name: env).each do |db_config|
|
588
593
|
next if name && name != db_config.name
|
589
594
|
|
@@ -592,6 +597,12 @@ module ActiveRecord
|
|
592
597
|
end
|
593
598
|
end
|
594
599
|
|
600
|
+
def each_current_environment(environment, &block)
|
601
|
+
environments = [environment]
|
602
|
+
environments << "test" if environment == "development" && !ENV["SKIP_TEST_DATABASE"] && !ENV["DATABASE_URL"]
|
603
|
+
environments.each(&block)
|
604
|
+
end
|
605
|
+
|
595
606
|
def each_local_configuration
|
596
607
|
configs_for.each do |db_config|
|
597
608
|
next unless db_config.database
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.2.0.
|
4
|
+
version: 7.2.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 7.2.0.
|
19
|
+
version: 7.2.0.rc1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.2.0.
|
26
|
+
version: 7.2.0.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 7.2.0.
|
33
|
+
version: 7.2.0.rc1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 7.2.0.
|
40
|
+
version: 7.2.0.rc1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: timeout
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -476,10 +476,10 @@ licenses:
|
|
476
476
|
- MIT
|
477
477
|
metadata:
|
478
478
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
479
|
-
changelog_uri: https://github.com/rails/rails/blob/v7.2.0.
|
480
|
-
documentation_uri: https://api.rubyonrails.org/v7.2.0.
|
479
|
+
changelog_uri: https://github.com/rails/rails/blob/v7.2.0.rc1/activerecord/CHANGELOG.md
|
480
|
+
documentation_uri: https://api.rubyonrails.org/v7.2.0.rc1/
|
481
481
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
482
|
-
source_code_uri: https://github.com/rails/rails/tree/v7.2.0.
|
482
|
+
source_code_uri: https://github.com/rails/rails/tree/v7.2.0.rc1/activerecord
|
483
483
|
rubygems_mfa_required: 'true'
|
484
484
|
post_install_message:
|
485
485
|
rdoc_options:
|