activerecord 7.1.5.1 → 8.0.2

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +369 -2484
  3. data/README.rdoc +15 -15
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +2 -1
  6. data/lib/active_record/associations/alias_tracker.rb +31 -23
  7. data/lib/active_record/associations/association.rb +43 -12
  8. data/lib/active_record/associations/belongs_to_association.rb +21 -8
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/association.rb +7 -6
  11. data/lib/active_record/associations/builder/belongs_to.rb +1 -0
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  13. data/lib/active_record/associations/builder/has_many.rb +3 -4
  14. data/lib/active_record/associations/builder/has_one.rb +3 -4
  15. data/lib/active_record/associations/collection_association.rb +17 -9
  16. data/lib/active_record/associations/collection_proxy.rb +14 -1
  17. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  18. data/lib/active_record/associations/errors.rb +265 -0
  19. data/lib/active_record/associations/has_many_association.rb +1 -1
  20. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  21. data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
  22. data/lib/active_record/associations/nested_error.rb +47 -0
  23. data/lib/active_record/associations/preloader/association.rb +4 -3
  24. data/lib/active_record/associations/preloader/branch.rb +7 -1
  25. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  26. data/lib/active_record/associations/singular_association.rb +14 -3
  27. data/lib/active_record/associations/through_association.rb +1 -1
  28. data/lib/active_record/associations.rb +92 -295
  29. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  30. data/lib/active_record/attribute_assignment.rb +0 -2
  31. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  32. data/lib/active_record/attribute_methods/primary_key.rb +25 -61
  33. data/lib/active_record/attribute_methods/read.rb +1 -13
  34. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  35. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
  36. data/lib/active_record/attribute_methods.rb +71 -75
  37. data/lib/active_record/attributes.rb +63 -49
  38. data/lib/active_record/autosave_association.rb +92 -57
  39. data/lib/active_record/base.rb +2 -3
  40. data/lib/active_record/callbacks.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
  42. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  43. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
  44. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
  45. data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
  46. data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
  47. data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
  48. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  49. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
  50. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
  51. data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
  52. data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
  53. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
  54. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  55. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
  56. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  57. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
  58. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
  59. data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
  60. data/lib/active_record/connection_adapters/pool_config.rb +14 -13
  61. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
  62. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  63. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  66. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  67. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  68. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
  69. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
  70. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
  71. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
  72. data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
  73. data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
  74. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  75. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
  76. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
  77. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
  78. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  79. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
  80. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
  81. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
  82. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  83. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
  84. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
  85. data/lib/active_record/connection_adapters.rb +65 -0
  86. data/lib/active_record/connection_handling.rb +74 -37
  87. data/lib/active_record/core.rb +132 -51
  88. data/lib/active_record/counter_cache.rb +19 -10
  89. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
  90. data/lib/active_record/database_configurations/database_config.rb +23 -4
  91. data/lib/active_record/database_configurations/hash_config.rb +46 -34
  92. data/lib/active_record/database_configurations/url_config.rb +20 -1
  93. data/lib/active_record/database_configurations.rb +1 -1
  94. data/lib/active_record/delegated_type.rb +41 -17
  95. data/lib/active_record/dynamic_matchers.rb +2 -2
  96. data/lib/active_record/encryption/config.rb +3 -1
  97. data/lib/active_record/encryption/encryptable_record.rb +7 -7
  98. data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
  99. data/lib/active_record/encryption/encryptor.rb +28 -6
  100. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  101. data/lib/active_record/encryption/key_provider.rb +1 -1
  102. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  103. data/lib/active_record/encryption/message_serializer.rb +4 -0
  104. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  105. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  106. data/lib/active_record/encryption/scheme.rb +8 -1
  107. data/lib/active_record/enum.rb +20 -16
  108. data/lib/active_record/errors.rb +54 -20
  109. data/lib/active_record/explain.rb +13 -24
  110. data/lib/active_record/fixtures.rb +37 -33
  111. data/lib/active_record/future_result.rb +21 -13
  112. data/lib/active_record/gem_version.rb +4 -4
  113. data/lib/active_record/inheritance.rb +4 -2
  114. data/lib/active_record/insert_all.rb +19 -16
  115. data/lib/active_record/integration.rb +4 -1
  116. data/lib/active_record/internal_metadata.rb +48 -34
  117. data/lib/active_record/locking/optimistic.rb +8 -7
  118. data/lib/active_record/log_subscriber.rb +5 -32
  119. data/lib/active_record/message_pack.rb +1 -1
  120. data/lib/active_record/migration/command_recorder.rb +33 -14
  121. data/lib/active_record/migration/compatibility.rb +8 -3
  122. data/lib/active_record/migration/default_strategy.rb +4 -5
  123. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  124. data/lib/active_record/migration.rb +104 -98
  125. data/lib/active_record/model_schema.rb +32 -70
  126. data/lib/active_record/nested_attributes.rb +15 -9
  127. data/lib/active_record/normalization.rb +3 -7
  128. data/lib/active_record/persistence.rb +127 -451
  129. data/lib/active_record/query_cache.rb +19 -8
  130. data/lib/active_record/query_logs.rb +104 -37
  131. data/lib/active_record/query_logs_formatter.rb +17 -28
  132. data/lib/active_record/querying.rb +24 -12
  133. data/lib/active_record/railtie.rb +26 -68
  134. data/lib/active_record/railties/controller_runtime.rb +13 -4
  135. data/lib/active_record/railties/databases.rake +43 -61
  136. data/lib/active_record/reflection.rb +112 -53
  137. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  138. data/lib/active_record/relation/batches.rb +138 -72
  139. data/lib/active_record/relation/calculations.rb +122 -82
  140. data/lib/active_record/relation/delegation.rb +30 -22
  141. data/lib/active_record/relation/finder_methods.rb +32 -18
  142. data/lib/active_record/relation/merger.rb +12 -14
  143. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  144. data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
  145. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  146. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  147. data/lib/active_record/relation/predicate_builder.rb +16 -3
  148. data/lib/active_record/relation/query_attribute.rb +1 -1
  149. data/lib/active_record/relation/query_methods.rb +317 -101
  150. data/lib/active_record/relation/spawn_methods.rb +3 -19
  151. data/lib/active_record/relation/where_clause.rb +7 -19
  152. data/lib/active_record/relation.rb +561 -119
  153. data/lib/active_record/result.rb +95 -46
  154. data/lib/active_record/runtime_registry.rb +39 -0
  155. data/lib/active_record/sanitization.rb +31 -25
  156. data/lib/active_record/schema.rb +8 -6
  157. data/lib/active_record/schema_dumper.rb +53 -20
  158. data/lib/active_record/schema_migration.rb +31 -14
  159. data/lib/active_record/scoping/named.rb +6 -2
  160. data/lib/active_record/signed_id.rb +24 -4
  161. data/lib/active_record/statement_cache.rb +19 -19
  162. data/lib/active_record/store.rb +7 -3
  163. data/lib/active_record/table_metadata.rb +2 -13
  164. data/lib/active_record/tasks/database_tasks.rb +87 -58
  165. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
  166. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  167. data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
  168. data/lib/active_record/test_fixtures.rb +98 -89
  169. data/lib/active_record/testing/query_assertions.rb +121 -0
  170. data/lib/active_record/timestamp.rb +2 -2
  171. data/lib/active_record/token_for.rb +22 -12
  172. data/lib/active_record/touch_later.rb +1 -1
  173. data/lib/active_record/transaction.rb +132 -0
  174. data/lib/active_record/transactions.rb +72 -17
  175. data/lib/active_record/translation.rb +0 -2
  176. data/lib/active_record/type/serialized.rb +1 -3
  177. data/lib/active_record/type_caster/connection.rb +4 -4
  178. data/lib/active_record/validations/associated.rb +9 -3
  179. data/lib/active_record/validations/uniqueness.rb +23 -18
  180. data/lib/active_record/validations.rb +4 -1
  181. data/lib/active_record.rb +138 -57
  182. data/lib/arel/alias_predication.rb +1 -1
  183. data/lib/arel/collectors/bind.rb +4 -2
  184. data/lib/arel/collectors/composite.rb +7 -0
  185. data/lib/arel/collectors/sql_string.rb +2 -2
  186. data/lib/arel/collectors/substitute_binds.rb +3 -3
  187. data/lib/arel/nodes/binary.rb +1 -7
  188. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  189. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  190. data/lib/arel/nodes/node.rb +5 -4
  191. data/lib/arel/nodes/sql_literal.rb +8 -1
  192. data/lib/arel/nodes.rb +2 -2
  193. data/lib/arel/predications.rb +1 -1
  194. data/lib/arel/select_manager.rb +1 -1
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/tree_manager.rb +3 -2
  197. data/lib/arel/update_manager.rb +2 -1
  198. data/lib/arel/visitors/dot.rb +1 -0
  199. data/lib/arel/visitors/mysql.rb +9 -4
  200. data/lib/arel/visitors/postgresql.rb +1 -12
  201. data/lib/arel/visitors/sqlite.rb +25 -0
  202. data/lib/arel/visitors/to_sql.rb +29 -16
  203. data/lib/arel.rb +7 -3
  204. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  205. metadata +18 -16
  206. data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -1,20 +1,16 @@
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.
7
11
  class ActiveRecordError < StandardError
8
12
  end
9
13
 
10
- # DEPRECATED: Previously raised when trying to use a feature in Active Record which
11
- # requires Active Job but the gem is not present. Now raises a NameError.
12
- include ActiveSupport::Deprecation::DeprecatedConstantAccessor
13
- DeprecatedActiveJobRequiredError = Class.new(ActiveRecordError) # :nodoc:
14
- deprecate_constant "ActiveJobRequiredError", "ActiveRecord::DeprecatedActiveJobRequiredError",
15
- message: "ActiveRecord::ActiveJobRequiredError has been deprecated. If Active Job is not present, a NameError will be raised instead.",
16
- deprecator: ActiveRecord.deprecator
17
-
18
14
  # Raised when the single-table inheritance mechanism fails to locate the subclass
19
15
  # (for example due to improper usage of column that
20
16
  # {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema::ClassMethods#inheritance_column]
@@ -66,7 +62,7 @@ module ActiveRecord
66
62
  end
67
63
 
68
64
  # Raised when connection to the database could not been established (for example when
69
- # {ActiveRecord::Base.connection=}[rdoc-ref:ConnectionHandling#connection]
65
+ # {ActiveRecord::Base.lease_connection=}[rdoc-ref:ConnectionHandling#lease_connection]
70
66
  # is given a +nil+ object).
71
67
  class ConnectionNotEstablished < AdapterError
72
68
  def initialize(message = nil, connection_pool: nil)
@@ -88,6 +84,19 @@ module ActiveRecord
88
84
  class ConnectionTimeoutError < ConnectionNotEstablished
89
85
  end
90
86
 
87
+ # Raised when a database connection pool is requested but
88
+ # has not been defined.
89
+ class ConnectionNotDefined < ConnectionNotEstablished
90
+ def initialize(message = nil, connection_name: nil, role: nil, shard: nil)
91
+ super(message)
92
+ @connection_name = connection_name
93
+ @role = role
94
+ @shard = shard
95
+ end
96
+
97
+ attr_reader :connection_name, :role, :shard
98
+ end
99
+
91
100
  # Raised when connection to the database could not been established because it was not
92
101
  # able to connect to the host or when the authorization failed.
93
102
  class DatabaseConnectionError < ConnectionNotEstablished
@@ -137,8 +146,18 @@ module ActiveRecord
137
146
  end
138
147
 
139
148
  # Raised by {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] and
140
- # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!]
141
- # methods when a record is invalid and cannot be saved.
149
+ # {ActiveRecord::Base.update_attribute!}[rdoc-ref:Persistence#update_attribute!]
150
+ # methods when a record failed to validate or cannot be saved due to any of the
151
+ # <tt>before_*</tt> callbacks throwing +:abort+. See
152
+ # ActiveRecord::Callbacks for further details.
153
+ #
154
+ # class Product < ActiveRecord::Base
155
+ # before_save do
156
+ # throw :abort if price < 0
157
+ # end
158
+ # end
159
+ #
160
+ # Product.create! # => raises an ActiveRecord::RecordNotSaved
142
161
  class RecordNotSaved < ActiveRecordError
143
162
  attr_reader :record
144
163
 
@@ -149,15 +168,17 @@ module ActiveRecord
149
168
  end
150
169
 
151
170
  # Raised by {ActiveRecord::Base#destroy!}[rdoc-ref:Persistence#destroy!]
152
- # when a call to {#destroy}[rdoc-ref:Persistence#destroy]
153
- # would return false.
171
+ # when a record cannot be destroyed due to any of the
172
+ # <tt>before_destroy</tt> callbacks throwing +:abort+. See
173
+ # ActiveRecord::Callbacks for further details.
154
174
  #
155
- # begin
156
- # complex_operation_that_internally_calls_destroy!
157
- # rescue ActiveRecord::RecordNotDestroyed => invalid
158
- # puts invalid.record.errors
175
+ # class User < ActiveRecord::Base
176
+ # before_destroy do
177
+ # throw :abort if still_active?
178
+ # end
159
179
  # end
160
180
  #
181
+ # User.first.destroy! # => raises an ActiveRecord::RecordNotDestroyed
161
182
  class RecordNotDestroyed < ActiveRecordError
162
183
  attr_reader :record
163
184
 
@@ -374,6 +395,12 @@ module ActiveRecord
374
395
  end
375
396
 
376
397
  # Raised on attempt to lazily load records that are marked as strict loading.
398
+ #
399
+ # You can resolve this error by eager loading marked records before accessing
400
+ # them. The
401
+ # {Eager Loading Associations}[https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations]
402
+ # guide covers solutions, such as using
403
+ # {ActiveRecord::Base.includes}[rdoc-ref:QueryMethods#includes].
377
404
  class StrictLoadingViolationError < ActiveRecordError
378
405
  end
379
406
 
@@ -466,9 +493,9 @@ module ActiveRecord
466
493
  # relation.loaded? # => true
467
494
  #
468
495
  # # Methods which try to mutate a loaded relation fail.
469
- # relation.where!(title: 'TODO') # => ActiveRecord::ImmutableRelation
470
- # relation.limit!(5) # => ActiveRecord::ImmutableRelation
471
- class ImmutableRelation < ActiveRecordError
496
+ # relation.where!(title: 'TODO') # => ActiveRecord::UnmodifiableRelation
497
+ # relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
498
+ class UnmodifiableRelation < ActiveRecordError
472
499
  end
473
500
 
474
501
  # TransactionIsolationError will be raised under the following conditions:
@@ -577,4 +604,11 @@ module ActiveRecord
577
604
  # values, such as request parameters or model attributes to query methods.
578
605
  class UnknownAttributeReference < ActiveRecordError
579
606
  end
607
+
608
+ # DatabaseVersionError will be raised when the database version is not supported, or when
609
+ # the database version cannot be determined.
610
+ class DatabaseVersionError < ActiveRecordError
611
+ end
580
612
  end
613
+
614
+ require "active_record/associations/errors"
@@ -17,16 +17,17 @@ module ActiveRecord
17
17
  # Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
18
18
  # Returns a formatted string ready to be logged.
19
19
  def exec_explain(queries, options = []) # :nodoc:
20
- str = queries.map do |sql, binds|
21
- msg = +"#{build_explain_clause(options)} #{sql}"
22
- unless binds.empty?
23
- msg << " "
24
- msg << binds.map { |attr| render_bind(attr) }.inspect
25
- end
26
- msg << "\n"
27
- msg << connection_explain(sql, binds, options)
28
- end.join("\n")
29
-
20
+ str = with_connection do |c|
21
+ queries.map do |sql, binds|
22
+ msg = +"#{build_explain_clause(c, options)} #{sql}"
23
+ unless binds.empty?
24
+ msg << " "
25
+ msg << binds.map { |attr| render_bind(c, attr) }.inspect
26
+ end
27
+ msg << "\n"
28
+ msg << c.explain(sql, binds, options)
29
+ end.join("\n")
30
+ end
30
31
  # Overriding inspect to be more human readable, especially in the console.
31
32
  def str.inspect
32
33
  self
@@ -36,7 +37,7 @@ module ActiveRecord
36
37
  end
37
38
 
38
39
  private
39
- def render_bind(attr)
40
+ def render_bind(connection, attr)
40
41
  if ActiveModel::Attribute === attr
41
42
  value = if attr.type.binary? && attr.value
42
43
  "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
@@ -51,24 +52,12 @@ module ActiveRecord
51
52
  [attr&.name, value]
52
53
  end
53
54
 
54
- def build_explain_clause(options = [])
55
+ def build_explain_clause(connection, options = [])
55
56
  if connection.respond_to?(:build_explain_clause, true)
56
57
  connection.build_explain_clause(options)
57
58
  else
58
59
  "EXPLAIN for:"
59
60
  end
60
61
  end
61
-
62
- def connection_explain(sql, binds, options)
63
- if connection.method(:explain).parameters.size == 2
64
- ActiveRecord.deprecator.warn(<<~MSG.squish)
65
- The current database adapter, #{connection.adapter_name}, does not support explain options.
66
- To remove this warning, the adapter must implement `build_explain_clause(options = [])`.
67
- MSG
68
- connection.explain(sql, binds)
69
- else
70
- connection.explain(sql, binds, options)
71
- end
72
- end
73
62
  end
74
63
  end
@@ -2,8 +2,6 @@
2
2
 
3
3
  require "erb"
4
4
  require "yaml"
5
- require "zlib"
6
- require "set"
7
5
  require "active_support/dependencies"
8
6
  require "active_support/core_ext/digest/uuid"
9
7
  require "active_record/test_fixtures"
@@ -110,6 +108,12 @@ module ActiveRecord
110
108
  # assert_raise(StandardError) { web_sites(:reddit) }
111
109
  # end
112
110
  #
111
+ # If the model names conflicts with a +TestCase+ methods, you can use the generic +fixture+ accessor
112
+ #
113
+ # test "generic find" do
114
+ # assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
115
+ # end
116
+ #
113
117
  # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
114
118
  # following tests:
115
119
  #
@@ -492,8 +496,8 @@ module ActiveRecord
492
496
  # # app/models/book_orders.rb
493
497
  # class BookOrder < ApplicationRecord
494
498
  # 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]
499
+ # belongs_to :order, foreign_key: [:shop_id, :order_id]
500
+ # belongs_to :book, foreign_key: [:author_id, :book_id]
497
501
  # end
498
502
  #
499
503
  # <code></code>
@@ -553,24 +557,24 @@ module ActiveRecord
553
557
  @@all_cached_fixtures.clear
554
558
  end
555
559
 
556
- def cache_for_connection(connection)
557
- @@all_cached_fixtures[connection]
560
+ def cache_for_connection_pool(connection_pool)
561
+ @@all_cached_fixtures[connection_pool]
558
562
  end
559
563
 
560
- def fixture_is_cached?(connection, table_name)
561
- cache_for_connection(connection)[table_name]
564
+ def fixture_is_cached?(connection_pool, table_name)
565
+ cache_for_connection_pool(connection_pool)[table_name]
562
566
  end
563
567
 
564
- def cached_fixtures(connection, keys_to_fetch = nil)
568
+ def cached_fixtures(connection_pool, keys_to_fetch = nil)
565
569
  if keys_to_fetch
566
- cache_for_connection(connection).values_at(*keys_to_fetch)
570
+ cache_for_connection_pool(connection_pool).values_at(*keys_to_fetch)
567
571
  else
568
- cache_for_connection(connection).values
572
+ cache_for_connection_pool(connection_pool).values
569
573
  end
570
574
  end
571
575
 
572
- def cache_fixtures(connection, fixtures_map)
573
- cache_for_connection(connection).update(fixtures_map)
576
+ def cache_fixtures(connection_pool, fixtures_map)
577
+ cache_for_connection_pool(connection_pool).update(fixtures_map)
574
578
  end
575
579
 
576
580
  def instantiate_fixtures(object, fixture_set, load_instances = true)
@@ -588,15 +592,13 @@ module ActiveRecord
588
592
  end
589
593
  end
590
594
 
591
- def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
595
+ def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
592
596
  fixture_set_names = Array(fixture_set_names).map(&:to_s)
593
597
  class_names.stringify_keys!
594
598
 
595
- # FIXME: Apparently JK uses this.
596
- connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
597
-
599
+ connection_pool = config.connection_pool
598
600
  fixture_files_to_read = fixture_set_names.reject do |fs_name|
599
- fixture_is_cached?(connection.call, fs_name)
601
+ fixture_is_cached?(connection_pool, fs_name)
600
602
  end
601
603
 
602
604
  if fixture_files_to_read.any?
@@ -604,11 +606,11 @@ module ActiveRecord
604
606
  Array(fixtures_directories),
605
607
  fixture_files_to_read,
606
608
  class_names,
607
- connection,
609
+ connection_pool,
608
610
  )
609
- cache_fixtures(connection.call, fixtures_map)
611
+ cache_fixtures(connection_pool, fixtures_map)
610
612
  end
611
- cached_fixtures(connection.call, fixture_set_names)
613
+ cached_fixtures(connection_pool, fixture_set_names)
612
614
  end
613
615
 
614
616
  # Returns a consistent, platform-independent identifier for +label+.
@@ -641,7 +643,7 @@ module ActiveRecord
641
643
  end
642
644
 
643
645
  private
644
- def read_and_insert(fixtures_directories, fixture_files, class_names, connection) # :nodoc:
646
+ def read_and_insert(fixtures_directories, fixture_files, class_names, connection_pool) # :nodoc:
645
647
  fixtures_map = {}
646
648
  directory_glob = "{#{fixtures_directories.join(",")}}"
647
649
  fixture_sets = fixture_files.map do |fixture_set_name|
@@ -655,21 +657,21 @@ module ActiveRecord
655
657
  end
656
658
  update_all_loaded_fixtures(fixtures_map)
657
659
 
658
- insert(fixture_sets, connection)
660
+ insert(fixture_sets, connection_pool)
659
661
 
660
662
  fixtures_map
661
663
  end
662
664
 
663
- def insert(fixture_sets, connection) # :nodoc:
664
- fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
665
+ def insert(fixture_sets, connection_pool) # :nodoc:
666
+ fixture_sets_by_pool = fixture_sets.group_by do |fixture_set|
665
667
  if fixture_set.model_class
666
- fixture_set.model_class.connection
668
+ fixture_set.model_class.connection_pool
667
669
  else
668
- connection.call
670
+ connection_pool
669
671
  end
670
672
  end
671
673
 
672
- fixture_sets_by_connection.each do |conn, set|
674
+ fixture_sets_by_pool.each do |pool, set|
673
675
  table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
674
676
 
675
677
  set.each do |fixture_set|
@@ -678,13 +680,15 @@ module ActiveRecord
678
680
  end
679
681
  end
680
682
 
681
- conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
683
+ pool.with_connection do |conn|
684
+ conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
682
685
 
683
- check_all_foreign_keys_valid!(conn)
686
+ check_all_foreign_keys_valid!(conn)
684
687
 
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) }
688
+ # Cap primary key sequences to max(pk).
689
+ if conn.respond_to?(:reset_pk_sequence!)
690
+ set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
691
+ end
688
692
  end
689
693
  end
690
694
  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
 
@@ -98,17 +100,21 @@ module ActiveRecord
98
100
  def execute_or_skip
99
101
  return unless pending?
100
102
 
101
- @pool.with_connection do |connection|
102
- return unless @mutex.try_lock
103
- begin
104
- if pending?
105
- @event_buffer = EventBuffer.new(self, @instrumenter)
106
- connection.with_instrumenter(@event_buffer) do
103
+ @session.synchronize do
104
+ return unless pending?
105
+
106
+ @pool.with_connection do |connection|
107
+ return unless @mutex.try_lock
108
+ begin
109
+ if pending?
110
+ @event_buffer = EventBuffer.new(self, @instrumenter)
111
+ ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] = @event_buffer
112
+
107
113
  execute_query(connection, async: true)
108
114
  end
115
+ ensure
116
+ @mutex.unlock
109
117
  end
110
- ensure
111
- @mutex.unlock
112
118
  end
113
119
  end
114
120
  end
@@ -140,7 +146,9 @@ module ActiveRecord
140
146
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
141
147
  @mutex.synchronize do
142
148
  if pending?
143
- execute_query(@pool.connection)
149
+ @pool.with_connection do |connection|
150
+ execute_query(connection)
151
+ end
144
152
  else
145
153
  @lock_wait = (Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start)
146
154
  end
@@ -159,7 +167,7 @@ module ActiveRecord
159
167
  end
160
168
 
161
169
  def exec_query(connection, *args, **kwargs)
162
- connection.internal_exec_query(*args, **kwargs)
170
+ connection.raw_exec_query(*args, **kwargs)
163
171
  end
164
172
 
165
173
  class SelectAll < FutureResult # :nodoc:
@@ -7,10 +7,10 @@ module ActiveRecord
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 7
11
- MINOR = 1
12
- TINY = 5
13
- PRE = "1"
10
+ MAJOR = 8
11
+ MINOR = 0
12
+ TINY = 2
13
+ PRE = nil
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
@@ -237,7 +240,7 @@ module ActiveRecord
237
240
 
238
241
  values_list = insert_all.map_key_with_value do |key, value|
239
242
  next value if Arel::Nodes::SqlLiteral === value
240
- connection.with_yaml_fallback(types[key].serialize(value))
243
+ ActiveModel::Type::SerializeCastValue.serialize(type = types[key], type.cast(value))
241
244
  end
242
245
 
243
246
  connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
@@ -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