activerecord 7.1.4.1 → 7.2.2.1

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 (189) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +643 -2274
  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 +15 -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 +7 -1
  15. data/lib/active_record/associations/collection_proxy.rb +14 -1
  16. data/lib/active_record/associations/errors.rb +265 -0
  17. data/lib/active_record/associations/has_many_association.rb +1 -1
  18. data/lib/active_record/associations/has_many_through_association.rb +7 -1
  19. data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
  20. data/lib/active_record/associations/join_dependency.rb +4 -4
  21. data/lib/active_record/associations/nested_error.rb +47 -0
  22. data/lib/active_record/associations/preloader/association.rb +2 -1
  23. data/lib/active_record/associations/preloader/branch.rb +7 -1
  24. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  25. data/lib/active_record/associations/singular_association.rb +6 -0
  26. data/lib/active_record/associations/through_association.rb +1 -1
  27. data/lib/active_record/associations.rb +59 -292
  28. data/lib/active_record/attribute_assignment.rb +0 -2
  29. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  30. data/lib/active_record/attribute_methods/primary_key.rb +23 -55
  31. data/lib/active_record/attribute_methods/read.rb +1 -13
  32. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  33. data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
  34. data/lib/active_record/attribute_methods.rb +54 -63
  35. data/lib/active_record/attributes.rb +61 -47
  36. data/lib/active_record/autosave_association.rb +12 -29
  37. data/lib/active_record/base.rb +2 -3
  38. data/lib/active_record/callbacks.rb +1 -1
  39. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
  40. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
  41. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +270 -65
  42. data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
  43. data/lib/active_record/connection_adapters/abstract/query_cache.rb +189 -74
  44. data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
  45. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  46. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +15 -6
  47. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
  48. data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -44
  49. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +40 -10
  50. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  51. data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
  52. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +6 -0
  53. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +16 -15
  54. data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -23
  55. data/lib/active_record/connection_adapters/pool_config.rb +7 -6
  56. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
  57. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  58. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  59. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  60. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  61. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
  62. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +17 -11
  63. data/lib/active_record/connection_adapters/postgresql_adapter.rb +29 -24
  64. data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
  65. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  66. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
  67. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
  68. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  69. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  70. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  71. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
  72. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -75
  73. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
  74. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
  75. data/lib/active_record/connection_adapters.rb +121 -0
  76. data/lib/active_record/connection_handling.rb +56 -41
  77. data/lib/active_record/core.rb +86 -38
  78. data/lib/active_record/counter_cache.rb +18 -9
  79. data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
  80. data/lib/active_record/database_configurations/database_config.rb +19 -4
  81. data/lib/active_record/database_configurations/hash_config.rb +38 -34
  82. data/lib/active_record/database_configurations/url_config.rb +20 -1
  83. data/lib/active_record/database_configurations.rb +1 -1
  84. data/lib/active_record/delegated_type.rb +24 -0
  85. data/lib/active_record/dynamic_matchers.rb +2 -2
  86. data/lib/active_record/encryption/encryptable_record.rb +3 -3
  87. data/lib/active_record/encryption/encrypted_attribute_type.rb +24 -4
  88. data/lib/active_record/encryption/encryptor.rb +18 -3
  89. data/lib/active_record/encryption/key_provider.rb +1 -1
  90. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  91. data/lib/active_record/encryption/message_serializer.rb +4 -0
  92. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  93. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  94. data/lib/active_record/encryption.rb +2 -0
  95. data/lib/active_record/enum.rb +19 -2
  96. data/lib/active_record/errors.rb +46 -20
  97. data/lib/active_record/explain.rb +13 -24
  98. data/lib/active_record/fixtures.rb +37 -31
  99. data/lib/active_record/future_result.rb +8 -4
  100. data/lib/active_record/gem_version.rb +2 -2
  101. data/lib/active_record/inheritance.rb +4 -2
  102. data/lib/active_record/insert_all.rb +18 -15
  103. data/lib/active_record/integration.rb +4 -1
  104. data/lib/active_record/internal_metadata.rb +48 -34
  105. data/lib/active_record/locking/optimistic.rb +7 -6
  106. data/lib/active_record/log_subscriber.rb +0 -21
  107. data/lib/active_record/marshalling.rb +4 -1
  108. data/lib/active_record/message_pack.rb +1 -1
  109. data/lib/active_record/migration/command_recorder.rb +2 -3
  110. data/lib/active_record/migration/compatibility.rb +5 -3
  111. data/lib/active_record/migration/default_strategy.rb +4 -5
  112. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  113. data/lib/active_record/migration.rb +85 -76
  114. data/lib/active_record/model_schema.rb +32 -68
  115. data/lib/active_record/nested_attributes.rb +24 -5
  116. data/lib/active_record/normalization.rb +3 -7
  117. data/lib/active_record/persistence.rb +30 -352
  118. data/lib/active_record/query_cache.rb +19 -8
  119. data/lib/active_record/query_logs.rb +15 -0
  120. data/lib/active_record/querying.rb +21 -9
  121. data/lib/active_record/railtie.rb +42 -57
  122. data/lib/active_record/railties/controller_runtime.rb +13 -4
  123. data/lib/active_record/railties/databases.rake +40 -43
  124. data/lib/active_record/reflection.rb +98 -36
  125. data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
  126. data/lib/active_record/relation/batches.rb +14 -8
  127. data/lib/active_record/relation/calculations.rb +96 -63
  128. data/lib/active_record/relation/delegation.rb +8 -11
  129. data/lib/active_record/relation/finder_methods.rb +16 -2
  130. data/lib/active_record/relation/merger.rb +4 -6
  131. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  132. data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -3
  133. data/lib/active_record/relation/predicate_builder.rb +3 -3
  134. data/lib/active_record/relation/query_methods.rb +224 -58
  135. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  136. data/lib/active_record/relation/spawn_methods.rb +2 -18
  137. data/lib/active_record/relation/where_clause.rb +7 -19
  138. data/lib/active_record/relation.rb +496 -72
  139. data/lib/active_record/result.rb +31 -44
  140. data/lib/active_record/runtime_registry.rb +39 -0
  141. data/lib/active_record/sanitization.rb +24 -19
  142. data/lib/active_record/schema.rb +8 -6
  143. data/lib/active_record/schema_dumper.rb +19 -9
  144. data/lib/active_record/schema_migration.rb +30 -14
  145. data/lib/active_record/scoping/named.rb +1 -0
  146. data/lib/active_record/signed_id.rb +20 -1
  147. data/lib/active_record/statement_cache.rb +7 -7
  148. data/lib/active_record/table_metadata.rb +1 -10
  149. data/lib/active_record/tasks/database_tasks.rb +81 -42
  150. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  151. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  152. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
  153. data/lib/active_record/test_fixtures.rb +86 -89
  154. data/lib/active_record/testing/query_assertions.rb +121 -0
  155. data/lib/active_record/timestamp.rb +2 -2
  156. data/lib/active_record/token_for.rb +22 -12
  157. data/lib/active_record/touch_later.rb +1 -1
  158. data/lib/active_record/transaction.rb +132 -0
  159. data/lib/active_record/transactions.rb +70 -14
  160. data/lib/active_record/translation.rb +0 -2
  161. data/lib/active_record/type/serialized.rb +1 -3
  162. data/lib/active_record/type_caster/connection.rb +4 -4
  163. data/lib/active_record/validations/associated.rb +9 -3
  164. data/lib/active_record/validations/uniqueness.rb +15 -10
  165. data/lib/active_record/validations.rb +4 -1
  166. data/lib/active_record.rb +148 -39
  167. data/lib/arel/alias_predication.rb +1 -1
  168. data/lib/arel/collectors/bind.rb +2 -0
  169. data/lib/arel/collectors/composite.rb +7 -0
  170. data/lib/arel/collectors/sql_string.rb +1 -1
  171. data/lib/arel/collectors/substitute_binds.rb +1 -1
  172. data/lib/arel/nodes/binary.rb +0 -6
  173. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  174. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  175. data/lib/arel/nodes/node.rb +4 -3
  176. data/lib/arel/nodes/sql_literal.rb +7 -0
  177. data/lib/arel/nodes.rb +2 -2
  178. data/lib/arel/predications.rb +1 -1
  179. data/lib/arel/select_manager.rb +1 -1
  180. data/lib/arel/tree_manager.rb +3 -2
  181. data/lib/arel/update_manager.rb +2 -1
  182. data/lib/arel/visitors/dot.rb +1 -0
  183. data/lib/arel/visitors/mysql.rb +9 -4
  184. data/lib/arel/visitors/postgresql.rb +1 -12
  185. data/lib/arel/visitors/sqlite.rb +25 -0
  186. data/lib/arel/visitors/to_sql.rb +29 -16
  187. data/lib/arel.rb +7 -3
  188. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  189. metadata +18 -12
@@ -223,6 +223,13 @@ module ActiveRecord
223
223
  options.transform_keys! { |key| :"#{key[1..-1]}" }
224
224
 
225
225
  definitions.each { |name, values| _enum(name, values, **options) }
226
+
227
+ ActiveRecord.deprecator.warn(<<~MSG)
228
+ Defining enums with keyword arguments is deprecated and will be removed
229
+ in Rails 8.0. Positional arguments should be used instead:
230
+
231
+ #{definitions.map { |name, values| "enum :#{name}, #{values}" }.join("\n")}
232
+ MSG
226
233
  end
227
234
 
228
235
  private
@@ -233,6 +240,7 @@ module ActiveRecord
233
240
 
234
241
  def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
235
242
  assert_valid_enum_definition_values(values)
243
+ assert_valid_enum_options(options)
236
244
  # statuses = { }
237
245
  enum_values = ActiveSupport::HashWithIndifferentAccess.new
238
246
  name = name.to_s
@@ -245,9 +253,11 @@ module ActiveRecord
245
253
  detect_enum_conflict!(name, name)
246
254
  detect_enum_conflict!(name, "#{name}=")
247
255
 
248
- attribute(name, **options) do |subtype|
256
+ attribute(name, **options)
257
+
258
+ decorate_attributes([name]) do |_name, subtype|
249
259
  if subtype == ActiveModel::Type.default_value
250
- raise "Undeclared attribute type for enum '#{name}'. Enums must be" \
260
+ raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
251
261
  " backed by a database column or declared with an explicit type" \
252
262
  " via `attribute`."
253
263
  end
@@ -361,6 +371,13 @@ module ActiveRecord
361
371
  end
362
372
  end
363
373
 
374
+ def assert_valid_enum_options(options)
375
+ invalid_keys = options.keys & %i[_prefix _suffix _scopes _default _instance_methods]
376
+ unless invalid_keys.empty?
377
+ raise ArgumentError, "invalid option(s): #{invalid_keys.map(&:inspect).join(", ")}. Valid options are: :prefix, :suffix, :scopes, :default, :instance_methods, and :validate."
378
+ end
379
+ end
380
+
364
381
  ENUM_CONFLICT_MESSAGE = \
365
382
  "You tried to define an enum named \"%{enum}\" on the model \"%{klass}\", but " \
366
383
  "this will generate a %{type} method \"%{method}\", which is already defined " \
@@ -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)
@@ -137,8 +133,18 @@ module ActiveRecord
137
133
  end
138
134
 
139
135
  # 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.
136
+ # {ActiveRecord::Base.update_attribute!}[rdoc-ref:Persistence#update_attribute!]
137
+ # methods when a record failed to validate or cannot be saved due to any of the
138
+ # <tt>before_*</tt> callbacks throwing +:abort+. See
139
+ # ActiveRecord::Callbacks for further details.
140
+ #
141
+ # class Product < ActiveRecord::Base
142
+ # before_save do
143
+ # throw :abort if price < 0
144
+ # end
145
+ # end
146
+ #
147
+ # Product.create! # => raises an ActiveRecord::RecordNotSaved
142
148
  class RecordNotSaved < ActiveRecordError
143
149
  attr_reader :record
144
150
 
@@ -149,15 +155,17 @@ module ActiveRecord
149
155
  end
150
156
 
151
157
  # Raised by {ActiveRecord::Base#destroy!}[rdoc-ref:Persistence#destroy!]
152
- # when a call to {#destroy}[rdoc-ref:Persistence#destroy]
153
- # would return false.
158
+ # when a record cannot be destroyed due to any of the
159
+ # <tt>before_destroy</tt> callbacks throwing +:abort+. See
160
+ # ActiveRecord::Callbacks for further details.
154
161
  #
155
- # begin
156
- # complex_operation_that_internally_calls_destroy!
157
- # rescue ActiveRecord::RecordNotDestroyed => invalid
158
- # puts invalid.record.errors
162
+ # class User < ActiveRecord::Base
163
+ # before_destroy do
164
+ # throw :abort if still_active?
165
+ # end
159
166
  # end
160
167
  #
168
+ # User.first.destroy! # => raises an ActiveRecord::RecordNotDestroyed
161
169
  class RecordNotDestroyed < ActiveRecordError
162
170
  attr_reader :record
163
171
 
@@ -374,6 +382,12 @@ module ActiveRecord
374
382
  end
375
383
 
376
384
  # Raised on attempt to lazily load records that are marked as strict loading.
385
+ #
386
+ # You can resolve this error by eager loading marked records before accessing
387
+ # them. The
388
+ # {Eager Loading Associations}[https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations]
389
+ # guide covers solutions, such as using
390
+ # {ActiveRecord::Base.includes}[rdoc-ref:QueryMethods#includes].
377
391
  class StrictLoadingViolationError < ActiveRecordError
378
392
  end
379
393
 
@@ -466,10 +480,15 @@ module ActiveRecord
466
480
  # relation.loaded? # => true
467
481
  #
468
482
  # # 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
483
+ # relation.where!(title: 'TODO') # => ActiveRecord::UnmodifiableRelation
484
+ # relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
485
+ class UnmodifiableRelation < ActiveRecordError
472
486
  end
487
+ deprecate_constant(
488
+ :ImmutableRelation,
489
+ "ActiveRecord::UnmodifiableRelation",
490
+ deprecator: ActiveRecord.deprecator
491
+ )
473
492
 
474
493
  # TransactionIsolationError will be raised under the following conditions:
475
494
  #
@@ -577,4 +596,11 @@ module ActiveRecord
577
596
  # values, such as request parameters or model attributes to query methods.
578
597
  class UnknownAttributeReference < ActiveRecordError
579
598
  end
599
+
600
+ # DatabaseVersionError will be raised when the database version is not supported, or when
601
+ # the database version cannot be determined.
602
+ class DatabaseVersionError < ActiveRecordError
603
+ end
580
604
  end
605
+
606
+ 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
@@ -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,8 +8,8 @@ module ActiveRecord
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 1
12
- TINY = 4
11
+ MINOR = 2
12
+ TINY = 2
13
13
  PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -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