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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a80eeb42f7130f9c9b8f9b9980959b202c550f1cf958326ffb3364161435b5f
4
- data.tar.gz: b875a8e003cfce381c29733acf6c3f019ffed72a52a1f01be123913294ea31de
3
+ metadata.gz: e66951e81d8026bf99151e2232bd66141817a39c499a94f6fd00a7238514135e
4
+ data.tar.gz: 765f9e290a5a1b2a99062ac2d333bea4b5aa7a7817b19f3efb4f90745c00295b
5
5
  SHA512:
6
- metadata.gz: 0eb8b60fa9d521a514799b6e5f5a5d1adaac422270b20245849ade043cd45aa485d0a17b57d163c641bc3ae29fa5700dbfa11c55451858de0d0b1647a97a666b
7
- data.tar.gz: 68f46c24553e6c1f85751aa223a53e186abd1ec8a744e3803709552e33bbe757193498141af13b918646bc83b1bcb83bee5a2e58f3f1278d785e54a3c444ca32
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.
@@ -311,6 +311,10 @@ module ActiveRecord
311
311
  target.any? { |record| record.new_record? || record.changed? }
312
312
  end
313
313
 
314
+ def collection?
315
+ true
316
+ end
317
+
314
318
  private
315
319
  def transaction(&block)
316
320
  reflection.klass.transaction(&block)
@@ -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
- # [:index_errors]
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. `roles[2].level`.
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
- record = association && association.load_target
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
- result = nil
10
- with_raw_connection do |conn|
11
- result = if ExplainRegistry.collect? && prepared_statements
12
- unprepared_statement { super }
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 = if supports_virtual_columns?
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
- def table_structure_sql(table_name)
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
- columns_string = result.split("(", 2).last
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
- columns_string.split(",").map(&:strip)
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
@@ -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::ImmutableRelation
480
- # relation.limit!(5) # => ActiveRecord::ImmutableRelation
481
- class ImmutableRelation < ActiveRecordError
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
  #
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  MAJOR = 7
11
11
  MINOR = 2
12
12
  TINY = 0
13
- PRE = "beta3"
13
+ PRE = "rc1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -341,7 +341,13 @@ module ActiveRecord
341
341
 
342
342
  if start || finish
343
343
  records = records.filter do |record|
344
- (start.nil? || record.id >= start) && (finish.nil? || record.id <= finish)
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
- return primary_key.map { |pk| value.public_send(pk) } if primary_key.is_a?(Array)
61
-
62
- if value.respond_to?(primary_key)
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
- assert_mutability! # assert_mutability!
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
- assert_mutability!
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 assert_mutability!
1709
- raise ImmutableRelation if @loaded || @arel
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
- migrate
197
- dump_schema(db_config) if ActiveRecord.dump_schema_after_migration
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
- environments = [environment]
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.beta3
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-07-11 00:00:00.000000000 Z
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.beta3
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.beta3
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.beta3
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.beta3
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.beta3/activerecord/CHANGELOG.md
480
- documentation_uri: https://api.rubyonrails.org/v7.2.0.beta3/
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.beta3/activerecord
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: