activerecord 7.1.5.1 → 7.2.0.beta1

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.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +515 -2445
  3. data/README.rdoc +15 -15
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +1 -1
  6. data/lib/active_record/associations/alias_tracker.rb +25 -19
  7. data/lib/active_record/associations/association.rb +9 -8
  8. data/lib/active_record/associations/belongs_to_association.rb +14 -7
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/belongs_to.rb +1 -0
  11. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  12. data/lib/active_record/associations/builder/has_many.rb +3 -4
  13. data/lib/active_record/associations/builder/has_one.rb +3 -4
  14. data/lib/active_record/associations/collection_association.rb +6 -4
  15. data/lib/active_record/associations/collection_proxy.rb +14 -1
  16. data/lib/active_record/associations/has_many_association.rb +1 -1
  17. data/lib/active_record/associations/join_dependency/join_association.rb +29 -28
  18. data/lib/active_record/associations/join_dependency.rb +5 -5
  19. data/lib/active_record/associations/nested_error.rb +47 -0
  20. data/lib/active_record/associations/preloader/association.rb +2 -1
  21. data/lib/active_record/associations/preloader/branch.rb +7 -1
  22. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  23. data/lib/active_record/associations/singular_association.rb +6 -0
  24. data/lib/active_record/associations/through_association.rb +1 -1
  25. data/lib/active_record/associations.rb +33 -16
  26. data/lib/active_record/attribute_assignment.rb +1 -11
  27. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  28. data/lib/active_record/attribute_methods/dirty.rb +1 -1
  29. data/lib/active_record/attribute_methods/primary_key.rb +23 -55
  30. data/lib/active_record/attribute_methods/read.rb +4 -16
  31. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  32. data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -10
  33. data/lib/active_record/attribute_methods/write.rb +3 -3
  34. data/lib/active_record/attribute_methods.rb +60 -71
  35. data/lib/active_record/attributes.rb +55 -42
  36. data/lib/active_record/autosave_association.rb +13 -32
  37. data/lib/active_record/base.rb +2 -3
  38. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
  39. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
  40. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +248 -65
  41. data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
  42. data/lib/active_record/connection_adapters/abstract/query_cache.rb +159 -74
  43. data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  45. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +14 -5
  46. data/lib/active_record/connection_adapters/abstract/transaction.rb +60 -57
  47. data/lib/active_record/connection_adapters/abstract_adapter.rb +18 -46
  48. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +32 -6
  49. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  50. data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
  51. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -1
  52. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +11 -5
  53. data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -23
  54. data/lib/active_record/connection_adapters/pool_config.rb +7 -6
  55. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
  56. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  57. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  58. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  59. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  60. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
  61. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -13
  62. data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -21
  63. data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
  64. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  65. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
  66. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
  67. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  68. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  69. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  70. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
  71. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +107 -75
  72. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +12 -6
  73. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
  74. data/lib/active_record/connection_adapters.rb +121 -0
  75. data/lib/active_record/connection_handling.rb +56 -41
  76. data/lib/active_record/core.rb +53 -37
  77. data/lib/active_record/counter_cache.rb +18 -9
  78. data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
  79. data/lib/active_record/database_configurations/database_config.rb +15 -4
  80. data/lib/active_record/database_configurations/hash_config.rb +38 -34
  81. data/lib/active_record/database_configurations/url_config.rb +20 -1
  82. data/lib/active_record/database_configurations.rb +1 -1
  83. data/lib/active_record/delegated_type.rb +24 -0
  84. data/lib/active_record/dynamic_matchers.rb +2 -2
  85. data/lib/active_record/encryption/encryptable_record.rb +2 -2
  86. data/lib/active_record/encryption/encrypted_attribute_type.rb +22 -2
  87. data/lib/active_record/encryption/encryptor.rb +17 -2
  88. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  89. data/lib/active_record/encryption/message_serializer.rb +4 -0
  90. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  91. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  92. data/lib/active_record/encryption.rb +0 -2
  93. data/lib/active_record/enum.rb +10 -1
  94. data/lib/active_record/errors.rb +16 -11
  95. data/lib/active_record/explain.rb +13 -24
  96. data/lib/active_record/fixtures.rb +37 -31
  97. data/lib/active_record/future_result.rb +8 -4
  98. data/lib/active_record/gem_version.rb +3 -3
  99. data/lib/active_record/inheritance.rb +4 -2
  100. data/lib/active_record/insert_all.rb +18 -15
  101. data/lib/active_record/integration.rb +4 -1
  102. data/lib/active_record/internal_metadata.rb +48 -34
  103. data/lib/active_record/locking/optimistic.rb +7 -6
  104. data/lib/active_record/log_subscriber.rb +0 -21
  105. data/lib/active_record/marshalling.rb +1 -4
  106. data/lib/active_record/message_pack.rb +1 -1
  107. data/lib/active_record/migration/command_recorder.rb +2 -3
  108. data/lib/active_record/migration/compatibility.rb +5 -3
  109. data/lib/active_record/migration/default_strategy.rb +4 -5
  110. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  111. data/lib/active_record/migration.rb +85 -76
  112. data/lib/active_record/model_schema.rb +28 -68
  113. data/lib/active_record/nested_attributes.rb +13 -16
  114. data/lib/active_record/normalization.rb +3 -7
  115. data/lib/active_record/persistence.rb +30 -352
  116. data/lib/active_record/query_cache.rb +18 -6
  117. data/lib/active_record/query_logs.rb +15 -0
  118. data/lib/active_record/querying.rb +21 -9
  119. data/lib/active_record/railtie.rb +50 -62
  120. data/lib/active_record/railties/controller_runtime.rb +13 -4
  121. data/lib/active_record/railties/databases.rake +41 -44
  122. data/lib/active_record/reflection.rb +90 -35
  123. data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
  124. data/lib/active_record/relation/batches.rb +3 -3
  125. data/lib/active_record/relation/calculations.rb +94 -61
  126. data/lib/active_record/relation/delegation.rb +8 -11
  127. data/lib/active_record/relation/finder_methods.rb +16 -2
  128. data/lib/active_record/relation/merger.rb +4 -6
  129. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  130. data/lib/active_record/relation/predicate_builder.rb +3 -3
  131. data/lib/active_record/relation/query_methods.rb +196 -57
  132. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  133. data/lib/active_record/relation/spawn_methods.rb +2 -18
  134. data/lib/active_record/relation/where_clause.rb +7 -19
  135. data/lib/active_record/relation.rb +496 -72
  136. data/lib/active_record/result.rb +31 -44
  137. data/lib/active_record/runtime_registry.rb +39 -0
  138. data/lib/active_record/sanitization.rb +24 -19
  139. data/lib/active_record/schema.rb +8 -6
  140. data/lib/active_record/schema_dumper.rb +19 -9
  141. data/lib/active_record/schema_migration.rb +30 -14
  142. data/lib/active_record/signed_id.rb +11 -1
  143. data/lib/active_record/statement_cache.rb +7 -7
  144. data/lib/active_record/table_metadata.rb +1 -10
  145. data/lib/active_record/tasks/database_tasks.rb +76 -70
  146. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  147. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  148. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
  149. data/lib/active_record/test_fixtures.rb +81 -91
  150. data/lib/active_record/testing/query_assertions.rb +121 -0
  151. data/lib/active_record/timestamp.rb +1 -1
  152. data/lib/active_record/token_for.rb +22 -12
  153. data/lib/active_record/touch_later.rb +1 -1
  154. data/lib/active_record/transaction.rb +68 -0
  155. data/lib/active_record/transactions.rb +43 -14
  156. data/lib/active_record/translation.rb +0 -2
  157. data/lib/active_record/type/serialized.rb +1 -3
  158. data/lib/active_record/type_caster/connection.rb +4 -4
  159. data/lib/active_record/validations/associated.rb +9 -3
  160. data/lib/active_record/validations/uniqueness.rb +14 -10
  161. data/lib/active_record/validations.rb +4 -1
  162. data/lib/active_record.rb +149 -40
  163. data/lib/arel/alias_predication.rb +1 -1
  164. data/lib/arel/collectors/bind.rb +2 -0
  165. data/lib/arel/collectors/composite.rb +7 -0
  166. data/lib/arel/collectors/sql_string.rb +1 -1
  167. data/lib/arel/collectors/substitute_binds.rb +1 -1
  168. data/lib/arel/nodes/binary.rb +0 -6
  169. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  170. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  171. data/lib/arel/nodes/node.rb +4 -3
  172. data/lib/arel/nodes/sql_literal.rb +7 -0
  173. data/lib/arel/nodes.rb +2 -2
  174. data/lib/arel/predications.rb +1 -1
  175. data/lib/arel/select_manager.rb +1 -1
  176. data/lib/arel/tree_manager.rb +3 -2
  177. data/lib/arel/update_manager.rb +2 -1
  178. data/lib/arel/visitors/dot.rb +1 -0
  179. data/lib/arel/visitors/mysql.rb +9 -4
  180. data/lib/arel/visitors/postgresql.rb +1 -12
  181. data/lib/arel/visitors/to_sql.rb +29 -16
  182. data/lib/arel.rb +7 -3
  183. metadata +20 -15
@@ -110,6 +110,12 @@ module ActiveRecord
110
110
  # assert_raise(StandardError) { web_sites(:reddit) }
111
111
  # end
112
112
  #
113
+ # If the model names conflicts with a +TestCase+ methods, you can use the generic +fixture+ accessor
114
+ #
115
+ # test "generic find" do
116
+ # assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
117
+ # end
118
+ #
113
119
  # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
114
120
  # following tests:
115
121
  #
@@ -492,8 +498,8 @@ module ActiveRecord
492
498
  # # app/models/book_orders.rb
493
499
  # class BookOrder < ApplicationRecord
494
500
  # self.primary_key = [:shop_id, :id]
495
- # belongs_to :order, query_constraints: [:shop_id, :order_id]
496
- # belongs_to :book, query_constraints: [:author_id, :book_id]
501
+ # belongs_to :order, foreign_key: [:shop_id, :order_id]
502
+ # belongs_to :book, foreign_key: [:author_id, :book_id]
497
503
  # end
498
504
  #
499
505
  # <code></code>
@@ -553,24 +559,24 @@ module ActiveRecord
553
559
  @@all_cached_fixtures.clear
554
560
  end
555
561
 
556
- def cache_for_connection(connection)
557
- @@all_cached_fixtures[connection]
562
+ def cache_for_connection_pool(connection_pool)
563
+ @@all_cached_fixtures[connection_pool]
558
564
  end
559
565
 
560
- def fixture_is_cached?(connection, table_name)
561
- cache_for_connection(connection)[table_name]
566
+ def fixture_is_cached?(connection_pool, table_name)
567
+ cache_for_connection_pool(connection_pool)[table_name]
562
568
  end
563
569
 
564
- def cached_fixtures(connection, keys_to_fetch = nil)
570
+ def cached_fixtures(connection_pool, keys_to_fetch = nil)
565
571
  if keys_to_fetch
566
- cache_for_connection(connection).values_at(*keys_to_fetch)
572
+ cache_for_connection_pool(connection_pool).values_at(*keys_to_fetch)
567
573
  else
568
- cache_for_connection(connection).values
574
+ cache_for_connection_pool(connection_pool).values
569
575
  end
570
576
  end
571
577
 
572
- def cache_fixtures(connection, fixtures_map)
573
- cache_for_connection(connection).update(fixtures_map)
578
+ def cache_fixtures(connection_pool, fixtures_map)
579
+ cache_for_connection_pool(connection_pool).update(fixtures_map)
574
580
  end
575
581
 
576
582
  def instantiate_fixtures(object, fixture_set, load_instances = true)
@@ -588,15 +594,13 @@ module ActiveRecord
588
594
  end
589
595
  end
590
596
 
591
- def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
597
+ def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
592
598
  fixture_set_names = Array(fixture_set_names).map(&:to_s)
593
599
  class_names.stringify_keys!
594
600
 
595
- # FIXME: Apparently JK uses this.
596
- connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
597
-
601
+ connection_pool = config.connection_pool
598
602
  fixture_files_to_read = fixture_set_names.reject do |fs_name|
599
- fixture_is_cached?(connection.call, fs_name)
603
+ fixture_is_cached?(connection_pool, fs_name)
600
604
  end
601
605
 
602
606
  if fixture_files_to_read.any?
@@ -604,11 +608,11 @@ module ActiveRecord
604
608
  Array(fixtures_directories),
605
609
  fixture_files_to_read,
606
610
  class_names,
607
- connection,
611
+ connection_pool,
608
612
  )
609
- cache_fixtures(connection.call, fixtures_map)
613
+ cache_fixtures(connection_pool, fixtures_map)
610
614
  end
611
- cached_fixtures(connection.call, fixture_set_names)
615
+ cached_fixtures(connection_pool, fixture_set_names)
612
616
  end
613
617
 
614
618
  # Returns a consistent, platform-independent identifier for +label+.
@@ -641,7 +645,7 @@ module ActiveRecord
641
645
  end
642
646
 
643
647
  private
644
- def read_and_insert(fixtures_directories, fixture_files, class_names, connection) # :nodoc:
648
+ def read_and_insert(fixtures_directories, fixture_files, class_names, connection_pool) # :nodoc:
645
649
  fixtures_map = {}
646
650
  directory_glob = "{#{fixtures_directories.join(",")}}"
647
651
  fixture_sets = fixture_files.map do |fixture_set_name|
@@ -655,21 +659,21 @@ module ActiveRecord
655
659
  end
656
660
  update_all_loaded_fixtures(fixtures_map)
657
661
 
658
- insert(fixture_sets, connection)
662
+ insert(fixture_sets, connection_pool)
659
663
 
660
664
  fixtures_map
661
665
  end
662
666
 
663
- def insert(fixture_sets, connection) # :nodoc:
664
- fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
667
+ def insert(fixture_sets, connection_pool) # :nodoc:
668
+ fixture_sets_by_pool = fixture_sets.group_by do |fixture_set|
665
669
  if fixture_set.model_class
666
- fixture_set.model_class.connection
670
+ fixture_set.model_class.connection_pool
667
671
  else
668
- connection.call
672
+ connection_pool
669
673
  end
670
674
  end
671
675
 
672
- fixture_sets_by_connection.each do |conn, set|
676
+ fixture_sets_by_pool.each do |pool, set|
673
677
  table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
674
678
 
675
679
  set.each do |fixture_set|
@@ -678,13 +682,15 @@ module ActiveRecord
678
682
  end
679
683
  end
680
684
 
681
- conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
685
+ pool.with_connection do |conn|
686
+ conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
682
687
 
683
- check_all_foreign_keys_valid!(conn)
688
+ check_all_foreign_keys_valid!(conn)
684
689
 
685
- # Cap primary key sequences to max(pk).
686
- if conn.respond_to?(:reset_pk_sequence!)
687
- set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
690
+ # Cap primary key sequences to max(pk).
691
+ if conn.respond_to?(:reset_pk_sequence!)
692
+ set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
693
+ end
688
694
  end
689
695
  end
690
696
  end
@@ -32,8 +32,11 @@ module ActiveRecord
32
32
 
33
33
  def instrument(name, payload = {}, &block)
34
34
  event = @instrumenter.new_event(name, payload)
35
- @events << event
36
- event.record(&block)
35
+ begin
36
+ event.record(&block)
37
+ ensure
38
+ @events << event
39
+ end
37
40
  end
38
41
 
39
42
  def flush
@@ -57,7 +60,6 @@ module ActiveRecord
57
60
  end
58
61
 
59
62
  delegate :empty?, :to_a, to: :result
60
- delegate_missing_to :result
61
63
 
62
64
  attr_reader :lock_wait
63
65
 
@@ -140,7 +142,9 @@ module ActiveRecord
140
142
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
141
143
  @mutex.synchronize do
142
144
  if pending?
143
- execute_query(@pool.connection)
145
+ @pool.with_connection do |connection|
146
+ execute_query(connection)
147
+ end
144
148
  else
145
149
  @lock_wait = (Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start)
146
150
  end
@@ -8,9 +8,9 @@ module ActiveRecord
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 1
12
- TINY = 5
13
- PRE = "1"
11
+ MINOR = 2
12
+ TINY = 0
13
+ PRE = "beta1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -165,7 +165,7 @@ module ActiveRecord
165
165
 
166
166
  # Returns whether this class is an abstract class or not.
167
167
  def abstract_class?
168
- defined?(@abstract_class) && @abstract_class == true
168
+ @abstract_class == true
169
169
  end
170
170
 
171
171
  # Sets the application record class for Active Record
@@ -202,7 +202,9 @@ module ActiveRecord
202
202
  "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
203
203
  "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
204
204
  "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
205
- "or overwrite #{name}.inheritance_column to use another column for that information."
205
+ "or overwrite #{name}.inheritance_column to use another column for that information. " \
206
+ "If you wish to disable single-table inheritance for #{name} set " \
207
+ "#{name}.inheritance_column to nil"
206
208
  end
207
209
 
208
210
  # Returns the value to be stored in the polymorphic type column for Polymorphic Associations.
@@ -7,8 +7,17 @@ module ActiveRecord
7
7
  attr_reader :model, :connection, :inserts, :keys
8
8
  attr_reader :on_duplicate, :update_only, :returning, :unique_by, :update_sql
9
9
 
10
- def initialize(model, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
11
- @model, @connection, @inserts = model, model.connection, inserts.map(&:stringify_keys)
10
+ class << self
11
+ def execute(relation, ...)
12
+ relation.model.with_connection do |c|
13
+ new(relation, c, ...).execute
14
+ end
15
+ end
16
+ end
17
+
18
+ def initialize(relation, connection, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
19
+ @relation = relation
20
+ @model, @connection, @inserts = relation.model, connection, inserts.map(&:stringify_keys)
12
21
  @on_duplicate, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by
13
22
  @record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps
14
23
 
@@ -23,10 +32,8 @@ module ActiveRecord
23
32
  @keys = @inserts.first.keys
24
33
  end
25
34
 
26
- if model.scope_attributes?
27
- @scope_attributes = model.scope_attributes
28
- @keys |= @scope_attributes.keys
29
- end
35
+ @scope_attributes = relation.scope_for_create.except(@model.inheritance_column)
36
+ @keys |= @scope_attributes.keys
30
37
  @keys = @keys.to_set
31
38
 
32
39
  @returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
@@ -52,10 +59,9 @@ module ActiveRecord
52
59
  end
53
60
 
54
61
  def primary_keys
55
- Array(connection.schema_cache.primary_keys(model.table_name))
62
+ Array(@model.schema_cache.primary_keys(model.table_name))
56
63
  end
57
64
 
58
-
59
65
  def skip_duplicates?
60
66
  on_duplicate == :skip
61
67
  end
@@ -67,7 +73,7 @@ module ActiveRecord
67
73
  def map_key_with_value
68
74
  inserts.map do |attributes|
69
75
  attributes = attributes.stringify_keys
70
- attributes.merge!(scope_attributes) if scope_attributes
76
+ attributes.merge!(@scope_attributes)
71
77
  attributes.reverse_merge!(timestamps_for_create) if record_timestamps?
72
78
 
73
79
  verify_attributes(attributes)
@@ -92,8 +98,6 @@ module ActiveRecord
92
98
  end
93
99
 
94
100
  private
95
- attr_reader :scope_attributes
96
-
97
101
  def has_attribute_aliases?(attributes)
98
102
  attributes.keys.any? { |attribute| model.attribute_alias?(attribute) }
99
103
  end
@@ -163,10 +167,9 @@ module ActiveRecord
163
167
  end
164
168
 
165
169
  def unique_indexes
166
- connection.schema_cache.indexes(model.table_name).select(&:unique)
170
+ @model.schema_cache.indexes(model.table_name).select(&:unique)
167
171
  end
168
172
 
169
-
170
173
  def ensure_valid_options_for_connection!
171
174
  if returning && !connection.supports_insert_returning?
172
175
  raise ArgumentError, "#{connection.class} does not support :returning"
@@ -192,7 +195,7 @@ module ActiveRecord
192
195
 
193
196
 
194
197
  def readonly_columns
195
- primary_keys + model.readonly_attributes.to_a
198
+ primary_keys + model.readonly_attributes
196
199
  end
197
200
 
198
201
  def unique_by_columns
@@ -301,7 +304,7 @@ module ActiveRecord
301
304
  end
302
305
 
303
306
  def extract_types_from_columns_on(table_name, keys:)
304
- columns = connection.schema_cache.columns_hash(table_name)
307
+ columns = @model.schema_cache.columns_hash(table_name)
305
308
 
306
309
  unknown_column = (keys - columns.keys).first
307
310
  raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
@@ -178,7 +178,10 @@ module ActiveRecord
178
178
  def can_use_fast_cache_version?(timestamp)
179
179
  timestamp.is_a?(String) &&
180
180
  cache_timestamp_format == :usec &&
181
- self.class.connection.default_timezone == :utc &&
181
+ # FIXME: checking out a connection for this is wasteful
182
+ # we should store/cache this information in the schema cache
183
+ # or similar.
184
+ self.class.with_connection(&:default_timezone) == :utc &&
182
185
  !updated_at_came_from_user?
183
186
  end
184
187
 
@@ -13,17 +13,13 @@ module ActiveRecord
13
13
  class NullInternalMetadata # :nodoc:
14
14
  end
15
15
 
16
- attr_reader :connection, :arel_table
16
+ attr_reader :arel_table
17
17
 
18
- def initialize(connection)
19
- @connection = connection
18
+ def initialize(pool)
19
+ @pool = pool
20
20
  @arel_table = Arel::Table.new(table_name)
21
21
  end
22
22
 
23
- def enabled?
24
- connection.use_metadata_table?
25
- end
26
-
27
23
  def primary_key
28
24
  "key"
29
25
  end
@@ -36,50 +32,66 @@ module ActiveRecord
36
32
  "#{ActiveRecord::Base.table_name_prefix}#{ActiveRecord::Base.internal_metadata_table_name}#{ActiveRecord::Base.table_name_suffix}"
37
33
  end
38
34
 
35
+ def enabled?
36
+ @pool.db_config.use_metadata_table?
37
+ end
38
+
39
39
  def []=(key, value)
40
40
  return unless enabled?
41
41
 
42
- update_or_create_entry(key, value)
42
+ @pool.with_connection do |connection|
43
+ update_or_create_entry(connection, key, value)
44
+ end
43
45
  end
44
46
 
45
47
  def [](key)
46
48
  return unless enabled?
47
49
 
48
- if entry = select_entry(key)
49
- entry[value_key]
50
+ @pool.with_connection do |connection|
51
+ if entry = select_entry(connection, key)
52
+ entry[value_key]
53
+ end
50
54
  end
51
55
  end
52
56
 
53
57
  def delete_all_entries
54
58
  dm = Arel::DeleteManager.new(arel_table)
55
59
 
56
- connection.delete(dm, "#{self.class} Destroy")
60
+ @pool.with_connection do |connection|
61
+ connection.delete(dm, "#{self.class} Destroy")
62
+ end
57
63
  end
58
64
 
59
65
  def count
60
66
  sm = Arel::SelectManager.new(arel_table)
61
67
  sm.project(*Arel::Nodes::Count.new([Arel.star]))
62
68
 
63
- connection.select_values(sm, "#{self.class} Count").first
69
+ @pool.with_connection do |connection|
70
+ connection.select_values(sm, "#{self.class} Count").first
71
+ end
64
72
  end
65
73
 
66
74
  def create_table_and_set_flags(environment, schema_sha1 = nil)
67
75
  return unless enabled?
68
76
 
69
- create_table
70
- update_or_create_entry(:environment, environment)
71
- update_or_create_entry(:schema_sha1, schema_sha1) if schema_sha1
77
+ @pool.with_connection do |connection|
78
+ create_table
79
+ update_or_create_entry(connection, :environment, environment)
80
+ update_or_create_entry(connection, :schema_sha1, schema_sha1) if schema_sha1
81
+ end
72
82
  end
73
83
 
74
84
  # Creates an internal metadata table with columns +key+ and +value+
75
85
  def create_table
76
86
  return unless enabled?
77
87
 
78
- unless connection.table_exists?(table_name)
79
- connection.create_table(table_name, id: false) do |t|
80
- t.string :key, **connection.internal_string_options_for_primary_key
81
- t.string :value
82
- t.timestamps
88
+ @pool.with_connection do |connection|
89
+ unless connection.table_exists?(table_name)
90
+ connection.create_table(table_name, id: false) do |t|
91
+ t.string :key, **connection.internal_string_options_for_primary_key
92
+ t.string :value
93
+ t.timestamps
94
+ end
83
95
  end
84
96
  end
85
97
  end
@@ -87,49 +99,51 @@ module ActiveRecord
87
99
  def drop_table
88
100
  return unless enabled?
89
101
 
90
- connection.drop_table table_name, if_exists: true
102
+ @pool.with_connection do |connection|
103
+ connection.drop_table table_name, if_exists: true
104
+ end
91
105
  end
92
106
 
93
107
  def table_exists?
94
- connection.schema_cache.data_source_exists?(table_name)
108
+ @pool.schema_cache.data_source_exists?(table_name)
95
109
  end
96
110
 
97
111
  private
98
- def update_or_create_entry(key, value)
99
- entry = select_entry(key)
112
+ def update_or_create_entry(connection, key, value)
113
+ entry = select_entry(connection, key)
100
114
 
101
115
  if entry
102
116
  if entry[value_key] != value
103
- update_entry(key, value)
117
+ update_entry(connection, key, value)
104
118
  else
105
119
  entry[value_key]
106
120
  end
107
121
  else
108
- create_entry(key, value)
122
+ create_entry(connection, key, value)
109
123
  end
110
124
  end
111
125
 
112
- def current_time
126
+ def current_time(connection)
113
127
  connection.default_timezone == :utc ? Time.now.utc : Time.now
114
128
  end
115
129
 
116
- def create_entry(key, value)
130
+ def create_entry(connection, key, value)
117
131
  im = Arel::InsertManager.new(arel_table)
118
132
  im.insert [
119
133
  [arel_table[primary_key], key],
120
134
  [arel_table[value_key], value],
121
- [arel_table[:created_at], current_time],
122
- [arel_table[:updated_at], current_time]
135
+ [arel_table[:created_at], current_time(connection)],
136
+ [arel_table[:updated_at], current_time(connection)]
123
137
  ]
124
138
 
125
139
  connection.insert(im, "#{self.class} Create", primary_key, key)
126
140
  end
127
141
 
128
- def update_entry(key, new_value)
142
+ def update_entry(connection, key, new_value)
129
143
  um = Arel::UpdateManager.new(arel_table)
130
144
  um.set [
131
145
  [arel_table[value_key], new_value],
132
- [arel_table[:updated_at], current_time]
146
+ [arel_table[:updated_at], current_time(connection)]
133
147
  ]
134
148
 
135
149
  um.where(arel_table[primary_key].eq(key))
@@ -137,9 +151,9 @@ module ActiveRecord
137
151
  connection.update(um, "#{self.class} Update")
138
152
  end
139
153
 
140
- def select_entry(key)
154
+ def select_entry(connection, key)
141
155
  sm = Arel::SelectManager.new(arel_table)
142
- sm.project(Arel::Nodes::SqlLiteral.new("*"))
156
+ sm.project(Arel::Nodes::SqlLiteral.new("*", retryable: true))
143
157
  sm.where(arel_table[primary_key].eq(Arel::Nodes::BindParam.new(key)))
144
158
  sm.order(arel_table[primary_key].asc)
145
159
  sm.limit = 1
@@ -182,14 +182,15 @@ module ActiveRecord
182
182
  super
183
183
  end
184
184
 
185
- def define_attribute(name, cast_type, **) # :nodoc:
186
- if lock_optimistically && name == locking_column
187
- cast_type = LockingType.new(cast_type)
185
+ private
186
+ def hook_attribute_type(name, cast_type)
187
+ if lock_optimistically && name == locking_column
188
+ cast_type = LockingType.new(cast_type)
189
+ end
190
+
191
+ super
188
192
  end
189
- super
190
- end
191
193
 
192
- private
193
194
  def inherited(base)
194
195
  super
195
196
  base.class_eval do
@@ -6,27 +6,6 @@ module ActiveRecord
6
6
 
7
7
  class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
8
8
 
9
- def self.runtime=(value)
10
- ActiveRecord.deprecator.warn(<<-MSG.squish)
11
- ActiveRecord::LogSubscriber.runtime= is deprecated and will be removed in Rails 7.2.
12
- MSG
13
- ActiveRecord::RuntimeRegistry.sql_runtime = value
14
- end
15
-
16
- def self.runtime
17
- ActiveRecord.deprecator.warn(<<-MSG.squish)
18
- ActiveRecord::LogSubscriber.runtime is deprecated and will be removed in Rails 7.2.
19
- MSG
20
- ActiveRecord::RuntimeRegistry.sql_runtime
21
- end
22
-
23
- def self.reset_runtime
24
- ActiveRecord.deprecator.warn(<<-MSG.squish)
25
- ActiveRecord::LogSubscriber.reset_runtime is deprecated and will be removed in Rails 7.2.
26
- MSG
27
- ActiveRecord::RuntimeRegistry.reset
28
- end
29
-
30
9
  def strict_loading_violation(event)
31
10
  debug do
32
11
  owner = event.payload[:owner]
@@ -25,10 +25,7 @@ module ActiveRecord
25
25
  payload = [attributes_for_database, new_record?]
26
26
 
27
27
  cached_associations = self.class.reflect_on_all_associations.select do |reflection|
28
- if association_cached?(reflection.name)
29
- association = association(reflection.name)
30
- association.loaded? || association.target.present?
31
- end
28
+ association_cached?(reflection.name) && association(reflection.name).loaded?
32
29
  end
33
30
 
34
31
  unless cached_associations.empty?
@@ -79,7 +79,7 @@ module ActiveRecord
79
79
  end
80
80
 
81
81
  def add_cached_associations(record, entry)
82
- record.class.reflections.each_value do |reflection|
82
+ record.class.normalized_reflections.each_value do |reflection|
83
83
  if record.association_cached?(reflection.name) && record.association(reflection.name).loaded?
84
84
  entry << reflection.name << encode(record.association(reflection.name).target)
85
85
  end
@@ -377,14 +377,13 @@ module ActiveRecord
377
377
  end
378
378
 
379
379
  # Forwards any missing method call to the \target.
380
- def method_missing(method, *args, &block)
380
+ def method_missing(method, ...)
381
381
  if delegate.respond_to?(method)
382
- delegate.public_send(method, *args, &block)
382
+ delegate.public_send(method, ...)
383
383
  else
384
384
  super
385
385
  end
386
386
  end
387
- ruby2_keywords(:method_missing)
388
387
  end
389
388
  end
390
389
  end
@@ -21,8 +21,7 @@ module ActiveRecord
21
21
  # New migration functionality that will never be backward compatible should be added directly to `ActiveRecord::Migration`.
22
22
  #
23
23
  # There are classes for each prior Rails version. Each class descends from the *next* Rails version, so:
24
- # 7.0 < 7.1
25
- # 5.2 < 6.0 < 6.1 < 7.0 < 7.1
24
+ # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2
26
25
  #
27
26
  # If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
28
27
  # find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
@@ -30,7 +29,10 @@ module ActiveRecord
30
29
  # For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
31
30
  # class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
32
31
  # for migrations written for 5.2, but will for migrations written for 6.0.
33
- V7_1 = Current
32
+ V7_2 = Current
33
+
34
+ class V7_1 < V7_2
35
+ end
34
36
 
35
37
  class V7_0 < V7_1
36
38
  module LegacyIndexName
@@ -6,13 +6,12 @@ module ActiveRecord
6
6
  # to the connection adapter.
7
7
  class DefaultStrategy < ExecutionStrategy # :nodoc:
8
8
  private
9
- def method_missing(method, *arguments, &block)
10
- connection.send(method, *arguments, &block)
9
+ def method_missing(method, ...)
10
+ connection.send(method, ...)
11
11
  end
12
- ruby2_keywords(:method_missing)
13
12
 
14
- def respond_to_missing?(method, *)
15
- connection.respond_to?(method) || super
13
+ def respond_to_missing?(method, include_private = false)
14
+ connection.respond_to?(method, include_private) || super
16
15
  end
17
16
 
18
17
  def connection
@@ -2,10 +2,10 @@
2
2
 
3
3
  module ActiveRecord
4
4
  class PendingMigrationConnection # :nodoc:
5
- def self.establish_temporary_connection(db_config, &block)
5
+ def self.with_temporary_pool(db_config, &block)
6
6
  pool = ActiveRecord::Base.connection_handler.establish_connection(db_config, owner_name: self)
7
7
 
8
- yield pool.connection
8
+ yield pool
9
9
  ensure
10
10
  ActiveRecord::Base.connection_handler.remove_connection_pool(self.name)
11
11
  end