activerecord 7.0.4.3 → 7.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +104 -7
  3. data/lib/active_record/associations/has_one_association.rb +4 -0
  4. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  5. data/lib/active_record/associations/singular_association.rb +7 -5
  6. data/lib/active_record/associations.rb +15 -6
  7. data/lib/active_record/attribute_methods/read.rb +1 -1
  8. data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -4
  9. data/lib/active_record/attribute_methods.rb +5 -7
  10. data/lib/active_record/callbacks.rb +12 -14
  11. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +20 -16
  12. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1 -0
  13. data/lib/active_record/connection_adapters/abstract_adapter.rb +4 -0
  14. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +7 -3
  15. data/lib/active_record/connection_adapters/mysql/quoting.rb +8 -0
  16. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
  17. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  18. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -5
  19. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  20. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
  21. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +3 -2
  22. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  23. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -1
  24. data/lib/active_record/disable_joins_association_relation.rb +1 -1
  25. data/lib/active_record/explain_subscriber.rb +1 -1
  26. data/lib/active_record/gem_version.rb +2 -2
  27. data/lib/active_record/middleware/database_selector.rb +3 -3
  28. data/lib/active_record/migration/command_recorder.rb +1 -2
  29. data/lib/active_record/migration/compatibility.rb +7 -0
  30. data/lib/active_record/migration.rb +1 -1
  31. data/lib/active_record/relation/calculations.rb +50 -23
  32. data/lib/active_record/relation/predicate_builder.rb +2 -1
  33. data/lib/active_record/relation/query_methods.rb +3 -3
  34. data/lib/active_record/schema_dumper.rb +4 -0
  35. data/lib/active_record/store.rb +1 -1
  36. data/lib/active_record/type/serialized.rb +4 -4
  37. data/lib/arel/filter_predications.rb +1 -1
  38. data/lib/arel/nodes/filter.rb +1 -1
  39. metadata +13 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1843d8f02a5d07f57fce55b1b30a097c2544aee0a3bf6b4a3b607fe8b5722c5
4
- data.tar.gz: 26ec900241ea5ac33a26eb695e970f50384215bcceade7b31ff9b7ab7da7ffc3
3
+ metadata.gz: f3039efb205667bcd9fc218b22042ee4a8f36b735f62fedf208a56b70bb3bd5c
4
+ data.tar.gz: df54f94c2480c583f2236f31de29f55525ee8f281fea93b30690f57f775d758b
5
5
  SHA512:
6
- metadata.gz: 10ab5e977258e62e32c71f893378b130fa980da5340e30c62a1150f57945605ba3c41fad811729f9bea5088581fc1d01cf64cad7312654efdd012e0b2df8111a
7
- data.tar.gz: 97d7537041f85e7ecfd7d035c3fd37df74e5cd3031993ee69342e7500c350c1dbc78cb9d248b05cc304fd0d6ca98e8b38747a98cb202c7138394c08f44849f85
6
+ metadata.gz: a412b99cef7bb68b569f14be355f715f888f0072f33436d40ffe8e4c90c088539d0fd1d26d43e508d5e6a2089ad7a73874f1aef7094bc7dc5287bccca753496b
7
+ data.tar.gz: 4b6008f67510a941efad31e7cddc4f6af2a7149da4a68cb248ce5481631c674216204d0a0028686c36a8f61f4366b1b2c096c5a6fd8ea61d29884bc57822a0fe
data/CHANGELOG.md CHANGED
@@ -1,3 +1,100 @@
1
+ ## Rails 7.0.5 (May 24, 2023) ##
2
+
3
+ * Type cast `#attribute_changed?` `:from` and `:to` options.
4
+
5
+ *Andrew Novoselac*
6
+
7
+ * Fix `index_exists?` when column is an array.
8
+
9
+ *Eileen M. Uchitelle*
10
+
11
+ * Handle `Date` objects for PostgreSQL `timestamptz` columns.
12
+
13
+ *Alex Ghiculescu*
14
+
15
+ * Fix collation for changing column to non-string.
16
+
17
+ *Hartley McGuire*
18
+
19
+ * Map through subtype in `PostgreSQL::OID::Array`.
20
+
21
+ *Jonathan Hefner*
22
+
23
+ * Store correct environment in `internal_metadata` when run rails `db:prepare`.
24
+
25
+ *fatkodima*
26
+
27
+ * Make sure `ActiveRecord::Relation#sum` works with objects that implement `#coerce` without deprecation.
28
+
29
+ *Alex Ghiculescu*
30
+
31
+ * Fix retrieving foreign keys referencing tables named like keywords in PostgreSQL and MySQL.
32
+
33
+ *fatkodima*
34
+
35
+ * Support UUIDs in Disable Joins.
36
+
37
+ *Samuel Cochran*
38
+
39
+ * Fix Active Record's explain for queries starting with comments.
40
+
41
+ *fatkodima*
42
+
43
+ * Fix incorrectly preloading through association records when middle association has been loaded.
44
+
45
+ *Joshua Young*
46
+
47
+ * Fix where.missing and where.associated for parent/child associations.
48
+
49
+ *fatkodima*
50
+
51
+ * Fix Enumerable#in_order_of to preserve duplicates.
52
+
53
+ *fatkodima*
54
+
55
+ * Fix autoincrement on primary key for mysql.
56
+
57
+ *Eileen M. Uchitelle*
58
+
59
+ * Restore ability to redefine column in `create_table` for Rails 5.2 migrations.
60
+
61
+ *fatkodima*
62
+
63
+ * Fix schema cache dumping of virtual columns.
64
+
65
+ *fatkodima*
66
+
67
+ * Fix Active Record grouped calculations on joined tables on column present in both tables.
68
+
69
+ *fatkodima*
70
+
71
+ * Fix mutation detection for serialized attributes backed by binary columns.
72
+
73
+ *Jean Boussier*
74
+
75
+ * Fix a bug where using groups and counts with long table names would return incorrect results.
76
+
77
+ *Shota Toguchi*, *Yusaku Ono*
78
+
79
+ * Use connection from `#with_raw_connection` in `#quote_string`.
80
+
81
+ Prior to this change, virtual datetime columns did not have the same
82
+ default precision as regular datetime columns, resulting in the following
83
+ being erroneously equivalent:
84
+
85
+ t.virtual :name, type: datetime, as: "expression"
86
+ t.virtual :name, type: datetime, precision: nil, as: "expression"
87
+
88
+ This change fixes the default precision lookup, so virtual and regular
89
+ datetime column default precisions match.
90
+
91
+ *Sam Bostock*
92
+
93
+ * Fix a case where the query cache can return wrong values. See #46044
94
+
95
+ *Aaron Patterson*
96
+
97
+
1
98
  ## Rails 7.0.4.3 (March 13, 2023) ##
2
99
 
3
100
  * No changes.
@@ -17,7 +114,7 @@
17
114
  carefully crafted input.
18
115
 
19
116
  This commit makes the sanitization more robust by replacing any
20
- occurrances of "/*" or "*/" with "/ *" or "* /". It also performs a
117
+ occurrences of "/*" or "*/" with "/ *" or "* /". It also performs a
21
118
  first pass to remove one surrounding comment to avoid compatibility
22
119
  issues for users relying on the existing removal.
23
120
 
@@ -142,21 +239,21 @@
142
239
 
143
240
  This adds two new configuration options The configuration options are as
144
241
  follows:
145
-
146
- * `config.active_storage.use_yaml_unsafe_load`
147
-
242
+
243
+ * `config.active_record.use_yaml_unsafe_load`
244
+
148
245
  When set to true, this configuration option tells Rails to use the old
149
246
  "unsafe" YAML loading strategy, maintaining the existing behavior but leaving
150
247
  the possible escalation vulnerability in place. Setting this option to true
151
248
  is *not* recommended, but can aid in upgrading.
152
-
249
+
153
250
  * `config.active_record.yaml_column_permitted_classes`
154
-
251
+
155
252
  The "safe YAML" loading method does not allow all classes to be deserialized
156
253
  by default. This option allows you to specify classes deemed "safe" in your
157
254
  application. For example, if your application uses Symbol and Time in
158
255
  serialized data, you can add Symbol and Time to the allowed list as follows:
159
-
256
+
160
257
  ```
161
258
  config.active_record.yaml_column_permitted_classes = [Symbol, Date, Time]
162
259
  ```
@@ -87,6 +87,10 @@ module ActiveRecord
87
87
  replace(record, false)
88
88
  end
89
89
 
90
+ def replace_keys(record, force: false)
91
+ # Has one association doesn't have foreign keys to replace.
92
+ end
93
+
90
94
  def remove_target!(method)
91
95
  case method
92
96
  when :delete
@@ -74,7 +74,7 @@ module ActiveRecord
74
74
  end
75
75
 
76
76
  def middle_records
77
- through_preloaders.flat_map(&:preloaded_records)
77
+ through_records_by_owner.values.flatten
78
78
  end
79
79
 
80
80
  def through_preloaders
@@ -54,11 +54,13 @@ module ActiveRecord
54
54
  end
55
55
 
56
56
  def _create_record(attributes, raise_error = false, &block)
57
- record = build_record(attributes, &block)
58
- saved = record.save
59
- set_new_record(record)
60
- raise RecordInvalid.new(record) if !saved && raise_error
61
- record
57
+ reflection.klass.transaction do
58
+ record = build(attributes, &block)
59
+ saved = record.save
60
+ replace_keys(record, force: true)
61
+ raise RecordInvalid.new(record) if !saved && raise_error
62
+ record
63
+ end
62
64
  end
63
65
  end
64
66
  end
@@ -586,8 +586,11 @@ module ActiveRecord
586
586
  # has_many :birthday_events, ->(user) { where(starts_on: user.birthday) }, class_name: 'Event'
587
587
  # end
588
588
  #
589
- # Note: Joining, eager loading, and preloading of these associations is not possible.
590
- # These operations happen before instance creation and the scope will be called with a +nil+ argument.
589
+ # Note: Joining or eager loading such associations is not possible because
590
+ # those operations happen before instance creation. Such associations
591
+ # _can_ be preloaded, but doing so will perform N+1 queries because there
592
+ # will be a different scope for each record (similar to preloading
593
+ # polymorphic scopes).
591
594
  #
592
595
  # == Association callbacks
593
596
  #
@@ -1600,6 +1603,12 @@ module ActiveRecord
1600
1603
  #
1601
1604
  # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
1602
1605
  # <tt>:autosave</tt> to <tt>true</tt>.
1606
+ # [:touch]
1607
+ # If true, the associated object will be touched (the +updated_at+ / +updated_on+ attributes set to current time)
1608
+ # when this record is either saved or destroyed. If you specify a symbol, that attribute
1609
+ # will be updated with the current time in addition to the +updated_at+ / +updated_on+ attribute.
1610
+ # Please note that no validation will be performed when touching, and only the +after_touch+,
1611
+ # +after_commit+, and +after_rollback+ callbacks will be executed.
1603
1612
  # [:inverse_of]
1604
1613
  # Specifies the name of the #belongs_to association on the associated object
1605
1614
  # that is the inverse of this #has_one association.
@@ -1747,11 +1756,11 @@ module ActiveRecord
1747
1756
  # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for
1748
1757
  # sets <tt>:autosave</tt> to <tt>true</tt>.
1749
1758
  # [:touch]
1750
- # If true, the associated object will be touched (the updated_at/on attributes set to current time)
1759
+ # If true, the associated object will be touched (the +updated_at+ / +updated_on+ attributes set to current time)
1751
1760
  # when this record is either saved or destroyed. If you specify a symbol, that attribute
1752
- # will be updated with the current time in addition to the updated_at/on attribute.
1753
- # Please note that with touching no validation is performed and only the +after_touch+,
1754
- # +after_commit+ and +after_rollback+ callbacks are executed.
1761
+ # will be updated with the current time in addition to the +updated_at+ / +updated_on+ attribute.
1762
+ # Please note that no validation will be performed when touching, and only the +after_touch+,
1763
+ # +after_commit+, and +after_rollback+ callbacks will be executed.
1755
1764
  # [:inverse_of]
1756
1765
  # Specifies the name of the #has_one or #has_many association on the associated
1757
1766
  # object that is the inverse of this #belongs_to association.
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
 
24
24
  # Returns the value of the attribute identified by <tt>attr_name</tt> after
25
25
  # it has been typecast (for example, "2004-12-12" in a date column is cast
26
- # to a date object, like Date.new(2004, 12, 12)).
26
+ # to a date object, like <tt>Date.new(2004, 12, 12)</tt>).
27
27
  def read_attribute(attr_name, &block)
28
28
  name = attr_name.to_s
29
29
  name = self.class.attribute_aliases[name] || name
@@ -19,8 +19,6 @@ module ActiveRecord
19
19
 
20
20
  if value.is_a?(Hash)
21
21
  set_time_zone_without_conversion(super)
22
- elsif value.is_a?(Range)
23
- Range.new(user_input_in_time_zone(value.begin), user_input_in_time_zone(value.end), value.exclude_end?)
24
22
  elsif value.respond_to?(:in_time_zone)
25
23
  begin
26
24
  super(user_input_in_time_zone(value)) || super
@@ -42,8 +40,6 @@ module ActiveRecord
42
40
  value.in_time_zone
43
41
  elsif value.respond_to?(:infinite?) && value.infinite?
44
42
  value
45
- elsif value.is_a?(Range)
46
- Range.new(convert_time_to_time_zone(value.begin), convert_time_to_time_zone(value.end), value.exclude_end?)
47
43
  else
48
44
  map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
49
45
  end
@@ -310,8 +310,8 @@ module ActiveRecord
310
310
  end
311
311
 
312
312
  # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
313
- # "2004-12-12" in a date column is cast to a date object, like Date.new(2004, 12, 12)). It raises
314
- # <tt>ActiveModel::MissingAttributeError</tt> if the identified attribute is missing.
313
+ # "2004-12-12" in a date column is cast to a date object, like <tt>Date.new(2004, 12, 12)</tt>). It raises
314
+ # ActiveModel::MissingAttributeError if the identified attribute is missing.
315
315
  #
316
316
  # Note: +:id+ is always present.
317
317
  #
@@ -331,7 +331,6 @@ module ActiveRecord
331
331
  end
332
332
 
333
333
  # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
334
- # (Alias for the protected #write_attribute method).
335
334
  #
336
335
  # class Person < ActiveRecord::Base
337
336
  # end
@@ -360,10 +359,9 @@ module ActiveRecord
360
359
  # end
361
360
  #
362
361
  # private
363
- #
364
- # def print_accessed_fields
365
- # p @posts.first.accessed_fields
366
- # end
362
+ # def print_accessed_fields
363
+ # p @posts.first.accessed_fields
364
+ # end
367
365
  # end
368
366
  #
369
367
  # Which allows you to quickly change your code to:
@@ -224,14 +224,13 @@ module ActiveRecord
224
224
  # after_save :do_something_else
225
225
  #
226
226
  # private
227
+ # def log_children
228
+ # # Child processing
229
+ # end
227
230
  #
228
- # def log_children
229
- # # Child processing
230
- # end
231
- #
232
- # def do_something_else
233
- # # Something else
234
- # end
231
+ # def do_something_else
232
+ # # Something else
233
+ # end
235
234
  # end
236
235
  #
237
236
  # In this case the +log_children+ is executed before +do_something_else+.
@@ -249,14 +248,13 @@ module ActiveRecord
249
248
  # after_commit :do_something_else
250
249
  #
251
250
  # private
251
+ # def log_children
252
+ # # Child processing
253
+ # end
252
254
  #
253
- # def log_children
254
- # # Child processing
255
- # end
256
- #
257
- # def do_something_else
258
- # # Something else
259
- # end
255
+ # def do_something_else
256
+ # # Something else
257
+ # end
260
258
  # end
261
259
  #
262
260
  # In this case the +do_something_else+ is executed before +log_children+.
@@ -411,20 +411,7 @@ module ActiveRecord
411
411
  name = name.to_s
412
412
  type = type.to_sym if type
413
413
 
414
- if @columns_hash[name]
415
- if @columns_hash[name].primary_key?
416
- raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
417
- else
418
- raise ArgumentError, "you can't define an already defined column '#{name}'."
419
- end
420
- end
421
-
422
- if @conn.supports_datetime_with_precision?
423
- if type == :datetime && !options.key?(:precision)
424
- options[:precision] = 6
425
- end
426
- end
427
-
414
+ raise_on_duplicate_column(name)
428
415
  @columns_hash[name] = new_column_definition(name, type, **options)
429
416
 
430
417
  if index
@@ -491,6 +478,13 @@ module ActiveRecord
491
478
  type = integer_like_primary_key_type(type, options)
492
479
  end
493
480
  type = aliased_types(type.to_s, type)
481
+
482
+ if @conn.supports_datetime_with_precision?
483
+ if type == :datetime && !options.key?(:precision)
484
+ options[:precision] = 6
485
+ end
486
+ end
487
+
494
488
  options[:primary_key] ||= type == :primary_key
495
489
  options[:null] = false if options[:primary_key]
496
490
  create_column_definition(name, type, options)
@@ -525,6 +519,16 @@ module ActiveRecord
525
519
  def integer_like_primary_key_type(type, options)
526
520
  type
527
521
  end
522
+
523
+ def raise_on_duplicate_column(name)
524
+ if @columns_hash[name]
525
+ if @columns_hash[name].primary_key?
526
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
527
+ else
528
+ raise ArgumentError, "you can't define an already defined column '#{name}'."
529
+ end
530
+ end
531
+ end
528
532
  end
529
533
 
530
534
  class AlterTable # :nodoc:
@@ -661,8 +665,8 @@ module ActiveRecord
661
665
  # end
662
666
  #
663
667
  # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
664
- def index_exists?(column_name, options = {})
665
- @base.index_exists?(name, column_name, options)
668
+ def index_exists?(column_name, **options)
669
+ @base.index_exists?(name, column_name, **options)
666
670
  end
667
671
 
668
672
  # Renames the given index on the table.
@@ -98,6 +98,7 @@ module ActiveRecord
98
98
  #
99
99
  def index_exists?(table_name, column_name, **options)
100
100
  checks = []
101
+ column_name = options[:column] if column_name.nil?
101
102
 
102
103
  if column_name.present?
103
104
  column_names = Array(column_name).map(&:to_s)
@@ -593,6 +593,10 @@ module ActiveRecord
593
593
  #
594
594
  # This is useful for when you need to call a proprietary method such as
595
595
  # PostgreSQL's lo_* methods.
596
+ #
597
+ # Active Record cannot track if the database is getting modified using
598
+ # this client. If that is the case, generally you'll want to invalidate
599
+ # the query cache using +ActiveRecord::Base.clear_query_cache+.
596
600
  def raw_connection
597
601
  disable_lazy_transactions!
598
602
  @connection
@@ -403,7 +403,7 @@ module ActiveRecord
403
403
 
404
404
  fk_info.map do |row|
405
405
  options = {
406
- column: row["column"],
406
+ column: unquote_identifier(row["column"]),
407
407
  name: row["name"],
408
408
  primary_key: row["primary_key"]
409
409
  }
@@ -411,7 +411,7 @@ module ActiveRecord
411
411
  options[:on_update] = extract_foreign_key_action(row["on_update"])
412
412
  options[:on_delete] = extract_foreign_key_action(row["on_delete"])
413
413
 
414
- ForeignKeyDefinition.new(table_name, row["to_table"], options)
414
+ ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
415
415
  end
416
416
  end
417
417
 
@@ -619,6 +619,10 @@ module ActiveRecord
619
619
  end
620
620
 
621
621
  private
622
+ def text_type?(type)
623
+ TYPE_MAP.lookup(type).is_a?(Type::String) || TYPE_MAP.lookup(type).is_a?(Type::Text)
624
+ end
625
+
622
626
  def type_map
623
627
  emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
624
628
  end
@@ -712,7 +716,7 @@ module ActiveRecord
712
716
  end
713
717
 
714
718
  unless options.key?(:collation)
715
- options[:collation] = column.collation
719
+ options[:collation] = column.collation if text_type?(type)
716
720
  end
717
721
 
718
722
  unless options.key?(:auto_increment)
@@ -51,6 +51,14 @@ module ActiveRecord
51
51
  "x'#{value.hex}'"
52
52
  end
53
53
 
54
+ def unquote_identifier(identifier)
55
+ if identifier && identifier.start_with?("`")
56
+ identifier[1..-2]
57
+ else
58
+ identifier
59
+ end
60
+ end
61
+
54
62
  # Override +type_cast+ we pass to mysql2 Date and Time objects instead
55
63
  # of Strings since mysql2 is able to handle those classes more efficiently.
56
64
  def type_cast(value) # :nodoc:
@@ -90,7 +90,10 @@ module ActiveRecord
90
90
  end
91
91
 
92
92
  def integer_like_primary_key_type(type, options)
93
- options[:auto_increment] = true
93
+ unless options[:auto_increment] == false
94
+ options[:auto_increment] = true
95
+ end
96
+
94
97
  type
95
98
  end
96
99
  end
@@ -42,11 +42,13 @@ module ActiveRecord
42
42
 
43
43
  def init_with(coder)
44
44
  @serial = coder["serial"]
45
+ @generated = coder["generated"]
45
46
  super
46
47
  end
47
48
 
48
49
  def encode_with(coder)
49
50
  coder["serial"] = @serial
51
+ coder["generated"] = @generated
50
52
  super
51
53
  end
52
54
 
@@ -57,11 +57,7 @@ module ActiveRecord
57
57
  fields.each_with_index do |fname, i|
58
58
  ftype = result.ftype i
59
59
  fmod = result.fmod i
60
- case type = get_oid_type(ftype, fmod, fname)
61
- when Type::Integer, Type::Float, OID::Decimal, Type::String, Type::DateTime, Type::Boolean
62
- # skip if a column has already been type casted by pg decoders
63
- else types[fname] = type
64
- end
60
+ types[fname] = get_oid_type(ftype, fmod, fname)
65
61
  end
66
62
  build_result(columns: fields, rows: result.values, column_types: types)
67
63
  end
@@ -65,7 +65,7 @@ module ActiveRecord
65
65
  end
66
66
 
67
67
  def map(value, &block)
68
- value.map(&block)
68
+ value.map { |v| subtype.map(v, &block) }
69
69
  end
70
70
 
71
71
  def changed_in_place?(raw_old_value, new_value)
@@ -13,7 +13,7 @@ module ActiveRecord
13
13
  return if value.blank?
14
14
 
15
15
  time = super
16
- return time if time.is_a?(ActiveSupport::TimeWithZone)
16
+ return time unless time.acts_like?(:time)
17
17
 
18
18
  # While in UTC mode, the PG gem may not return times back in "UTC" even if they were provided to Postgres in UTC.
19
19
  # We prefer times always in UTC, so here we convert back.
@@ -498,7 +498,7 @@ module ActiveRecord
498
498
 
499
499
  fk_info.map do |row|
500
500
  options = {
501
- column: row["column"],
501
+ column: Utils.unquote_identifier(row["column"]),
502
502
  name: row["name"],
503
503
  primary_key: row["primary_key"]
504
504
  }
@@ -508,8 +508,9 @@ module ActiveRecord
508
508
  options[:deferrable] = extract_foreign_key_deferrable(row["deferrable"], row["deferred"])
509
509
 
510
510
  options[:validate] = row["valid"]
511
+ to_table = Utils.unquote_identifier(row["to_table"])
511
512
 
512
- ForeignKeyDefinition.new(table_name, row["to_table"], options)
513
+ ForeignKeyDefinition.new(table_name, to_table, options)
513
514
  end
514
515
  end
515
516
 
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  attr_reader :schema, :identifier
13
13
 
14
14
  def initialize(schema, identifier)
15
- @schema, @identifier = unquote(schema), unquote(identifier)
15
+ @schema, @identifier = Utils.unquote_identifier(schema), Utils.unquote_identifier(identifier)
16
16
  end
17
17
 
18
18
  def to_s
@@ -40,15 +40,6 @@ module ActiveRecord
40
40
  def parts
41
41
  @parts ||= [@schema, @identifier].compact
42
42
  end
43
-
44
- private
45
- def unquote(part)
46
- if part && part.start_with?('"')
47
- part[1..-2]
48
- else
49
- part
50
- end
51
- end
52
43
  end
53
44
 
54
45
  module Utils # :nodoc:
@@ -74,6 +65,14 @@ module ActiveRecord
74
65
  end
75
66
  PostgreSQL::Name.new(schema, table)
76
67
  end
68
+
69
+ def unquote_identifier(identifier)
70
+ if identifier && identifier.start_with?('"')
71
+ identifier[1..-2]
72
+ else
73
+ identifier
74
+ end
75
+ end
77
76
  end
78
77
  end
79
78
  end
@@ -977,7 +977,7 @@ module ActiveRecord
977
977
  PG::TextDecoder::TimestampUtc :
978
978
  PG::TextDecoder::TimestampWithoutTimeZone
979
979
 
980
- @timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
980
+ @timestamp_decoder = decoder_class.new(**@timestamp_decoder.to_h)
981
981
  @connection.type_map_for_results.add_coder(@timestamp_decoder)
982
982
 
983
983
  @default_timezone = ActiveRecord.default_timezone
@@ -30,7 +30,7 @@ module ActiveRecord
30
30
  record[key]
31
31
  end
32
32
 
33
- records = ids.flat_map { |id| records_by_id[id.to_i] }
33
+ records = ids.flat_map { |id| records_by_id[id] }
34
34
  records.compact!
35
35
 
36
36
  @records = records
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # On the other hand, we want to monitor the performance of our real database
22
22
  # queries, not the performance of the access to the query cache.
23
23
  IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN)
24
- EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
24
+ EXPLAINED_SQLS = /\A\s*(\/\*.*\*\/)?\s*(with|select|update|delete|insert)\b/i
25
25
  def ignore_payload?(payload)
26
26
  payload[:exception] ||
27
27
  payload[:cached] ||
@@ -9,8 +9,8 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
- TINY = 4
13
- PRE = "3"
12
+ TINY = 5
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -43,9 +43,9 @@ module ActiveRecord
43
43
  # config.active_record.database_resolver = MyResolver
44
44
  # config.active_record.database_resolver_context = MyResolver::MySession
45
45
  #
46
- # Note: If you are using `rails new my_app --minimal` you will need to call
47
- # `require "active_support/core_ext/integer/time"` to load the libraries
48
- # for +Time+.
46
+ # Note: If you are using <tt>rails new my_app --minimal</tt> you will need
47
+ # to call <tt>require "active_support/core_ext/integer/time"</tt> to load
48
+ # the core extension in order to use +2.seconds+
49
49
  class DatabaseSelector
50
50
  def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
51
51
  @app = app
@@ -12,7 +12,6 @@ module ActiveRecord
12
12
  # * add_index
13
13
  # * add_reference
14
14
  # * add_timestamps
15
- # * change_column
16
15
  # * change_column_default (must supply a +:from+ and +:to+ option)
17
16
  # * change_column_null
18
17
  # * change_column_comment (must supply a +:from+ and +:to+ option)
@@ -24,7 +23,7 @@ module ActiveRecord
24
23
  # * drop_table (must supply a block)
25
24
  # * enable_extension
26
25
  # * remove_column (must supply a type)
27
- # * remove_columns (must specify at least one column name or more)
26
+ # * remove_columns (must supply a +:type+ option)
28
27
  # * remove_foreign_key (must supply a second table)
29
28
  # * remove_check_constraint
30
29
  # * remove_index
@@ -159,6 +159,13 @@ module ActiveRecord
159
159
  options[:precision] ||= nil
160
160
  super
161
161
  end
162
+
163
+ private
164
+ def raise_on_if_exist_options(options)
165
+ end
166
+
167
+ def raise_on_duplicate_column(name)
168
+ end
162
169
  end
163
170
 
164
171
  module CommandRecorder
@@ -1338,7 +1338,7 @@ module ActiveRecord
1338
1338
  # Stores the current environment in the database.
1339
1339
  def record_environment
1340
1340
  return if down?
1341
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1341
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.pool.db_config.env_name
1342
1342
  end
1343
1343
 
1344
1344
  def ran?(migration)
@@ -4,6 +4,47 @@ require "active_support/core_ext/enumerable"
4
4
 
5
5
  module ActiveRecord
6
6
  module Calculations
7
+ class ColumnAliasTracker # :nodoc:
8
+ def initialize(connection)
9
+ @connection = connection
10
+ @aliases = Hash.new(0)
11
+ end
12
+
13
+ def alias_for(field)
14
+ aliased_name = column_alias_for(field)
15
+
16
+ if @aliases[aliased_name] == 0
17
+ @aliases[aliased_name] = 1
18
+ aliased_name
19
+ else
20
+ # Update the count
21
+ count = @aliases[aliased_name] += 1
22
+ "#{truncate(aliased_name)}_#{count}"
23
+ end
24
+ end
25
+
26
+ private
27
+ # Converts the given field to the value that the database adapter returns as
28
+ # a usable column name:
29
+ #
30
+ # column_alias_for("users.id") # => "users_id"
31
+ # column_alias_for("sum(id)") # => "sum_id"
32
+ # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
33
+ # column_alias_for("count(*)") # => "count_all"
34
+ def column_alias_for(field)
35
+ column_alias = +field
36
+ column_alias.gsub!(/\*/, "all")
37
+ column_alias.gsub!(/\W+/, " ")
38
+ column_alias.strip!
39
+ column_alias.gsub!(/ +/, "_")
40
+ @connection.table_alias_for(column_alias)
41
+ end
42
+
43
+ def truncate(name)
44
+ name.slice(0, @connection.table_alias_length - 2)
45
+ end
46
+ end
47
+
7
48
  # Count the records.
8
49
  #
9
50
  # Person.count
@@ -86,7 +127,7 @@ module ActiveRecord
86
127
  def sum(identity_or_column = nil, &block)
87
128
  if block_given?
88
129
  values = map(&block)
89
- if identity_or_column.nil? && (values.first.is_a?(Numeric) || values.first(1) == [])
130
+ if identity_or_column.nil? && (values.first.is_a?(Numeric) || values.first(1) == [] || values.first.respond_to?(:coerce))
90
131
  identity_or_column = 0
91
132
  end
92
133
 
@@ -336,14 +377,16 @@ module ActiveRecord
336
377
  end
337
378
  group_fields = arel_columns(group_fields)
338
379
 
380
+ column_alias_tracker = ColumnAliasTracker.new(connection)
381
+
339
382
  group_aliases = group_fields.map { |field|
340
383
  field = connection.visitor.compile(field) if Arel.arel_node?(field)
341
- column_alias_for(field.to_s.downcase)
384
+ column_alias_tracker.alias_for(field.to_s.downcase)
342
385
  }
343
386
  group_columns = group_aliases.zip(group_fields)
344
387
 
345
388
  column = aggregate_column(column_name)
346
- column_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
389
+ column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
347
390
  select_value = operation_over_aggregate_column(column, operation, distinct)
348
391
  select_value.as(connection.quote_column_name(column_alias))
349
392
 
@@ -372,9 +415,10 @@ module ActiveRecord
372
415
  end
373
416
 
374
417
  key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
375
- types[aliaz] = type_for(col_name) do
376
- calculated_data.column_types.fetch(aliaz, Type.default_value)
377
- end
418
+ types[aliaz] = col_name.try(:type_caster) ||
419
+ type_for(col_name) do
420
+ calculated_data.column_types.fetch(aliaz, Type.default_value)
421
+ end
378
422
  end
379
423
 
380
424
  hash_rows = calculated_data.cast_values(key_types).map! do |row|
@@ -398,23 +442,6 @@ module ActiveRecord
398
442
  end
399
443
  end
400
444
 
401
- # Converts the given field to the value that the database adapter returns as
402
- # a usable column name:
403
- #
404
- # column_alias_for("users.id") # => "users_id"
405
- # column_alias_for("sum(id)") # => "sum_id"
406
- # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
407
- # column_alias_for("count(*)") # => "count_all"
408
- def column_alias_for(field)
409
- column_alias = +field
410
- column_alias.gsub!(/\*/, "all")
411
- column_alias.gsub!(/\W+/, " ")
412
- column_alias.strip!
413
- column_alias.gsub!(/ +/, "_")
414
-
415
- connection.table_alias_for(column_alias)
416
- end
417
-
418
445
  def type_for(field, &block)
419
446
  field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
420
447
  @klass.type_for_attribute(field_name, &block)
@@ -65,7 +65,8 @@ module ActiveRecord
65
65
  end
66
66
 
67
67
  def build_bind_attribute(column_name, value)
68
- Relation::QueryAttribute.new(column_name, value, table.type(column_name))
68
+ type = table.type(column_name)
69
+ Relation::QueryAttribute.new(column_name, type.immutable_value(value), type)
69
70
  end
70
71
 
71
72
  def resolve_arel_attribute(table_name, column_name, &block)
@@ -77,7 +77,7 @@ module ActiveRecord
77
77
  associations.each do |association|
78
78
  reflection = scope_association_reflection(association)
79
79
  @scope.joins!(association)
80
- self.not(reflection.table_name => { reflection.association_primary_key => nil })
80
+ self.not(association => { reflection.association_primary_key => nil })
81
81
  end
82
82
 
83
83
  @scope
@@ -105,7 +105,7 @@ module ActiveRecord
105
105
  associations.each do |association|
106
106
  reflection = scope_association_reflection(association)
107
107
  @scope.left_outer_joins!(association)
108
- @scope.where!(reflection.table_name => { reflection.association_primary_key => nil })
108
+ @scope.where!(association => { reflection.association_primary_key => nil })
109
109
  end
110
110
 
111
111
  @scope
@@ -289,7 +289,7 @@ module ActiveRecord
289
289
  # You can also use one or more strings, which will be used unchanged as SELECT fields.
290
290
  #
291
291
  # Model.select('field AS field_one', 'other_field AS field_two')
292
- # # => [#<Model id: nil, field: "value", other_field: "value">]
292
+ # # => [#<Model id: nil, field_one: "value", field_two: "value">]
293
293
  #
294
294
  # If an alias was specified, it will be accessible from the resulting objects:
295
295
  #
@@ -292,6 +292,10 @@ module ActiveRecord
292
292
  end
293
293
 
294
294
  def remove_prefix_and_suffix(table)
295
+ # This method appears at the top when profiling active_record test cases run.
296
+ # Avoid costly calculation when there are no prefix and suffix.
297
+ return table if @options[:table_name_prefix].blank? && @options[:table_name_suffix].blank?
298
+
295
299
  prefix = Regexp.escape(@options[:table_name_prefix].to_s)
296
300
  suffix = Regexp.escape(@options[:table_name_suffix].to_s)
297
301
  table.sub(/\A#{prefix}(.+)#{suffix}\z/, "\\1")
@@ -70,7 +70,7 @@ module ActiveRecord
70
70
  #
71
71
  # The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
72
72
  #
73
- # User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry]
73
+ # User.stored_attributes[:settings] # => [:color, :homepage, :two_factor_auth, :login_retry]
74
74
  #
75
75
  # == Overwriting default accessors
76
76
  #
@@ -63,11 +63,11 @@ module ActiveRecord
63
63
  def encoded(value)
64
64
  return if default_value?(value)
65
65
  payload = coder.dump(value)
66
- if payload && binary? && payload.encoding != Encoding::BINARY
67
- payload = payload.dup if payload.frozen?
68
- payload.force_encoding(Encoding::BINARY)
66
+ if payload && @subtype.binary?
67
+ ActiveModel::Type::Binary::Data.new(payload)
68
+ else
69
+ payload
69
70
  end
70
- payload
71
71
  end
72
72
  end
73
73
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Arel
3
+ module Arel # :nodoc: all
4
4
  module FilterPredications
5
5
  def filter(expr)
6
6
  Nodes::Filter.new(self, expr)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Arel
3
+ module Arel # :nodoc: all
4
4
  module Nodes
5
5
  class Filter < Binary
6
6
  include Arel::WindowPredications
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.0.4.3
4
+ version: 7.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-13 00:00:00.000000000 Z
11
+ date: 2023-05-24 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.0.4.3
19
+ version: 7.0.5
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.0.4.3
26
+ version: 7.0.5
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.0.4.3
33
+ version: 7.0.5
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.0.4.3
40
+ version: 7.0.5
41
41
  description: Databases on Rails. Build a persistent domain model by mapping database
42
42
  tables to Ruby classes. Strong conventions for associations, validations, aggregations,
43
43
  migrations, and testing come baked-in.
@@ -434,12 +434,12 @@ licenses:
434
434
  - MIT
435
435
  metadata:
436
436
  bug_tracker_uri: https://github.com/rails/rails/issues
437
- changelog_uri: https://github.com/rails/rails/blob/v7.0.4.3/activerecord/CHANGELOG.md
438
- documentation_uri: https://api.rubyonrails.org/v7.0.4.3/
437
+ changelog_uri: https://github.com/rails/rails/blob/v7.0.5/activerecord/CHANGELOG.md
438
+ documentation_uri: https://api.rubyonrails.org/v7.0.5/
439
439
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
440
- source_code_uri: https://github.com/rails/rails/tree/v7.0.4.3/activerecord
440
+ source_code_uri: https://github.com/rails/rails/tree/v7.0.5/activerecord
441
441
  rubygems_mfa_required: 'true'
442
- post_install_message:
442
+ post_install_message:
443
443
  rdoc_options:
444
444
  - "--main"
445
445
  - README.rdoc
@@ -456,8 +456,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
456
456
  - !ruby/object:Gem::Version
457
457
  version: '0'
458
458
  requirements: []
459
- rubygems_version: 3.4.3
460
- signing_key:
459
+ rubygems_version: 3.4.10
460
+ signing_key:
461
461
  specification_version: 4
462
462
  summary: Object-relational mapper framework (part of Rails).
463
463
  test_files: []