activerecord 7.2.0.beta3 → 7.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|