activerecord 7.2.0.beta3 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a80eeb42f7130f9c9b8f9b9980959b202c550f1cf958326ffb3364161435b5f
4
- data.tar.gz: b875a8e003cfce381c29733acf6c3f019ffed72a52a1f01be123913294ea31de
3
+ metadata.gz: 9ec33405aa24cc15f0f8a4092bc3a04acafc8191a4df5b41896ce648a5937687
4
+ data.tar.gz: 89efd888d4ed72e2d3ff6e75297c1dc4d0dcb19c15ed32c39fd53a2947a51b0b
5
5
  SHA512:
6
- metadata.gz: 0eb8b60fa9d521a514799b6e5f5a5d1adaac422270b20245849ade043cd45aa485d0a17b57d163c641bc3ae29fa5700dbfa11c55451858de0d0b1647a97a666b
7
- data.tar.gz: 68f46c24553e6c1f85751aa223a53e186abd1ec8a744e3803709552e33bbe757193498141af13b918646bc83b1bcb83bee5a2e58f3f1278d785e54a3c444ca32
6
+ metadata.gz: 84757d9eab7d9709fcd86d0e39d111f6fabf6dc09f15167c432c1ce097d87524e8839be9843eaf7b0be0acc53f92c92dafdae3e21df3c996a34eb01ca6f5703c
7
+ data.tar.gz: 83c46935ce453cec3e536ba27caa6b76fd5cdf59d8ca762e6eba91d2137a616d3a1e01cbfe049c945363130e55998e2afde0a8ff1d975ee2359ad38b560980ed
data/CHANGELOG.md CHANGED
@@ -1,4 +1,19 @@
1
- ## Rails 7.2.0.beta3 (July 11, 2024) ##
1
+ ## Rails 7.2.0 (August 09, 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*
2
17
 
3
18
  * Add condensed `#inspect` for `ConnectionPool`, `AbstractAdapter`, and
4
19
  `DatabaseConfig`.
@@ -23,9 +38,6 @@
23
38
 
24
39
  *Jay Ang*
25
40
 
26
-
27
- ## Rails 7.2.0.beta2 (June 04, 2024) ##
28
-
29
41
  * The payload of `sql.active_record` Active Support notifications now has the current transaction in the `:transaction` key.
30
42
 
31
43
  *Xavier Noria*
@@ -38,9 +50,6 @@
38
50
 
39
51
  *Xavier Noria*
40
52
 
41
-
42
- ## Rails 7.2.0.beta1 (May 29, 2024) ##
43
-
44
53
  * Fix inference of association model on nested models with the same demodularized name.
45
54
 
46
55
  E.g. with the following setup:
@@ -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 = nil
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
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-09 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
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
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
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
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/activerecord/CHANGELOG.md
480
+ documentation_uri: https://api.rubyonrails.org/v7.2.0/
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/activerecord
483
483
  rubygems_mfa_required: 'true'
484
484
  post_install_message:
485
485
  rdoc_options: