activerecord 6.1.7.7 → 7.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (220) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +726 -1389
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +31 -9
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +14 -23
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/preloader/association.rb +161 -47
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +41 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +2 -14
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
  62. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  63. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  65. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  66. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
  67. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  70. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  71. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -32
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  78. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  79. data/lib/active_record/connection_adapters/postgresql_adapter.rb +159 -102
  80. data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
  81. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
  82. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  83. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  84. data/lib/active_record/connection_adapters.rb +6 -5
  85. data/lib/active_record/connection_handling.rb +20 -38
  86. data/lib/active_record/core.rb +111 -125
  87. data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
  88. data/lib/active_record/database_configurations/database_config.rb +12 -0
  89. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  90. data/lib/active_record/database_configurations/url_config.rb +2 -2
  91. data/lib/active_record/database_configurations.rb +17 -9
  92. data/lib/active_record/delegated_type.rb +33 -11
  93. data/lib/active_record/destroy_association_async_job.rb +1 -1
  94. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  95. data/lib/active_record/dynamic_matchers.rb +1 -1
  96. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  97. data/lib/active_record/encryption/cipher.rb +53 -0
  98. data/lib/active_record/encryption/config.rb +44 -0
  99. data/lib/active_record/encryption/configurable.rb +61 -0
  100. data/lib/active_record/encryption/context.rb +35 -0
  101. data/lib/active_record/encryption/contexts.rb +72 -0
  102. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  103. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  104. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  105. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  106. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  107. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  108. data/lib/active_record/encryption/encryptor.rb +155 -0
  109. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  110. data/lib/active_record/encryption/errors.rb +15 -0
  111. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  112. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  113. data/lib/active_record/encryption/key.rb +28 -0
  114. data/lib/active_record/encryption/key_generator.rb +42 -0
  115. data/lib/active_record/encryption/key_provider.rb +46 -0
  116. data/lib/active_record/encryption/message.rb +33 -0
  117. data/lib/active_record/encryption/message_serializer.rb +80 -0
  118. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  119. data/lib/active_record/encryption/properties.rb +76 -0
  120. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  121. data/lib/active_record/encryption/scheme.rb +99 -0
  122. data/lib/active_record/encryption.rb +55 -0
  123. data/lib/active_record/enum.rb +41 -41
  124. data/lib/active_record/errors.rb +66 -3
  125. data/lib/active_record/fixture_set/file.rb +15 -1
  126. data/lib/active_record/fixture_set/table_row.rb +40 -5
  127. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  128. data/lib/active_record/fixtures.rb +16 -11
  129. data/lib/active_record/future_result.rb +139 -0
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +55 -17
  132. data/lib/active_record/insert_all.rb +34 -5
  133. data/lib/active_record/integration.rb +1 -1
  134. data/lib/active_record/internal_metadata.rb +1 -5
  135. data/lib/active_record/locking/optimistic.rb +10 -9
  136. data/lib/active_record/log_subscriber.rb +6 -2
  137. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  138. data/lib/active_record/middleware/database_selector.rb +8 -3
  139. data/lib/active_record/migration/command_recorder.rb +4 -4
  140. data/lib/active_record/migration/compatibility.rb +89 -10
  141. data/lib/active_record/migration/join_table.rb +1 -1
  142. data/lib/active_record/migration.rb +109 -79
  143. data/lib/active_record/model_schema.rb +45 -31
  144. data/lib/active_record/nested_attributes.rb +3 -3
  145. data/lib/active_record/no_touching.rb +2 -2
  146. data/lib/active_record/null_relation.rb +2 -6
  147. data/lib/active_record/persistence.rb +134 -45
  148. data/lib/active_record/query_cache.rb +2 -2
  149. data/lib/active_record/query_logs.rb +203 -0
  150. data/lib/active_record/querying.rb +15 -5
  151. data/lib/active_record/railtie.rb +117 -17
  152. data/lib/active_record/railties/controller_runtime.rb +1 -1
  153. data/lib/active_record/railties/databases.rake +72 -48
  154. data/lib/active_record/readonly_attributes.rb +11 -0
  155. data/lib/active_record/reflection.rb +45 -44
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  157. data/lib/active_record/relation/batches.rb +3 -3
  158. data/lib/active_record/relation/calculations.rb +39 -26
  159. data/lib/active_record/relation/delegation.rb +6 -6
  160. data/lib/active_record/relation/finder_methods.rb +31 -22
  161. data/lib/active_record/relation/merger.rb +20 -13
  162. data/lib/active_record/relation/predicate_builder.rb +1 -6
  163. data/lib/active_record/relation/query_attribute.rb +5 -11
  164. data/lib/active_record/relation/query_methods.rb +230 -49
  165. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  166. data/lib/active_record/relation/spawn_methods.rb +2 -2
  167. data/lib/active_record/relation/where_clause.rb +8 -4
  168. data/lib/active_record/relation.rb +166 -77
  169. data/lib/active_record/result.rb +17 -2
  170. data/lib/active_record/runtime_registry.rb +2 -4
  171. data/lib/active_record/sanitization.rb +11 -7
  172. data/lib/active_record/schema_dumper.rb +3 -3
  173. data/lib/active_record/schema_migration.rb +0 -4
  174. data/lib/active_record/scoping/default.rb +61 -12
  175. data/lib/active_record/scoping/named.rb +3 -11
  176. data/lib/active_record/scoping.rb +40 -22
  177. data/lib/active_record/serialization.rb +1 -1
  178. data/lib/active_record/signed_id.rb +1 -1
  179. data/lib/active_record/store.rb +1 -6
  180. data/lib/active_record/tasks/database_tasks.rb +106 -22
  181. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  182. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  183. data/lib/active_record/test_databases.rb +1 -1
  184. data/lib/active_record/test_fixtures.rb +9 -13
  185. data/lib/active_record/timestamp.rb +3 -4
  186. data/lib/active_record/transactions.rb +9 -14
  187. data/lib/active_record/translation.rb +2 -2
  188. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  189. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  190. data/lib/active_record/type/internal/timezone.rb +2 -2
  191. data/lib/active_record/type/serialized.rb +1 -1
  192. data/lib/active_record/type/type_map.rb +17 -20
  193. data/lib/active_record/type.rb +1 -2
  194. data/lib/active_record/validations/associated.rb +1 -1
  195. data/lib/active_record.rb +170 -2
  196. data/lib/arel/attributes/attribute.rb +0 -8
  197. data/lib/arel/crud.rb +18 -22
  198. data/lib/arel/delete_manager.rb +2 -4
  199. data/lib/arel/insert_manager.rb +2 -3
  200. data/lib/arel/nodes/casted.rb +1 -1
  201. data/lib/arel/nodes/delete_statement.rb +8 -13
  202. data/lib/arel/nodes/insert_statement.rb +2 -2
  203. data/lib/arel/nodes/select_core.rb +2 -2
  204. data/lib/arel/nodes/select_statement.rb +2 -2
  205. data/lib/arel/nodes/update_statement.rb +3 -2
  206. data/lib/arel/predications.rb +1 -1
  207. data/lib/arel/select_manager.rb +10 -4
  208. data/lib/arel/table.rb +0 -1
  209. data/lib/arel/tree_manager.rb +0 -12
  210. data/lib/arel/update_manager.rb +2 -4
  211. data/lib/arel/visitors/dot.rb +80 -90
  212. data/lib/arel/visitors/mysql.rb +6 -1
  213. data/lib/arel/visitors/postgresql.rb +0 -10
  214. data/lib/arel/visitors/to_sql.rb +43 -2
  215. data/lib/arel.rb +1 -1
  216. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  217. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  218. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  219. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  220. metadata +55 -17
@@ -63,6 +63,30 @@ module ActiveRecord
63
63
  class ConnectionTimeoutError < ConnectionNotEstablished
64
64
  end
65
65
 
66
+ # Raised when connection to the database could not been established because it was not
67
+ # able to connect to the host or when the authorization failed.
68
+ class DatabaseConnectionError < ConnectionNotEstablished
69
+ def initialize(message = nil)
70
+ super(message || "Database connection error")
71
+ end
72
+
73
+ class << self
74
+ def hostname_error(hostname)
75
+ DatabaseConnectionError.new(<<~MSG)
76
+ There is an issue connecting with your hostname: #{hostname}.\n
77
+ Please check your database configuration and ensure there is a valid connection to your database.
78
+ MSG
79
+ end
80
+
81
+ def username_error(username)
82
+ DatabaseConnectionError.new(<<~MSG)
83
+ There is an issue connecting to your database with your username/password, username: #{username}.\n
84
+ Please check your database configuration to ensure the username/password are valid.
85
+ MSG
86
+ end
87
+ end
88
+ end
89
+
66
90
  # Raised when a pool was unable to get ahold of all its connections
67
91
  # to perform a "group" action such as
68
92
  # {ActiveRecord::Base.connection_pool.disconnect!}[rdoc-ref:ConnectionAdapters::ConnectionPool#disconnect!]
@@ -100,7 +124,7 @@ module ActiveRecord
100
124
  end
101
125
 
102
126
  # Raised by {ActiveRecord::Base#destroy!}[rdoc-ref:Persistence#destroy!]
103
- # when a call to {#destroy}[rdoc-ref:Persistence#destroy!]
127
+ # when a call to {#destroy}[rdoc-ref:Persistence#destroy]
104
128
  # would return false.
105
129
  #
106
130
  # begin
@@ -118,6 +142,16 @@ module ActiveRecord
118
142
  end
119
143
  end
120
144
 
145
+ # Raised when Active Record finds multiple records but only expected one.
146
+ class SoleRecordExceeded < ActiveRecordError
147
+ attr_reader :record
148
+
149
+ def initialize(record = nil)
150
+ @record = record
151
+ super "Wanted only one #{record&.name || "record"}"
152
+ end
153
+ end
154
+
121
155
  # Superclass for all database execution errors.
122
156
  #
123
157
  # Wraps the underlying database error as +cause+.
@@ -202,6 +236,30 @@ module ActiveRecord
202
236
 
203
237
  # Raised when a given database does not exist.
204
238
  class NoDatabaseError < StatementInvalid
239
+ include ActiveSupport::ActionableError
240
+
241
+ action "Create database" do
242
+ ActiveRecord::Tasks::DatabaseTasks.create_current
243
+ end
244
+
245
+ def initialize(message = nil)
246
+ super(message || "Database not found")
247
+ end
248
+
249
+ class << self
250
+ def db_error(db_name)
251
+ NoDatabaseError.new(<<~MSG)
252
+ We could not find your database: #{db_name}. Which can be found in the database configuration file located at config/database.yml.
253
+
254
+ To resolve this issue:
255
+
256
+ - Did you create the database for this app, or delete it? You may need to create your database.
257
+ - Has the database name changed? Check your database.yml config has the correct database name.
258
+
259
+ To create your database, run:\n\n bin/rails db:create
260
+ MSG
261
+ end
262
+ end
205
263
  end
206
264
 
207
265
  # Raised when creating a database if it exists.
@@ -363,6 +421,11 @@ module ActiveRecord
363
421
  class TransactionRollbackError < StatementInvalid
364
422
  end
365
423
 
424
+ # AsynchronousQueryInsideTransactionError will be raised when attempting
425
+ # to perform an asynchronous query from inside a transaction
426
+ class AsynchronousQueryInsideTransactionError < ActiveRecordError
427
+ end
428
+
366
429
  # SerializationFailure will be raised when a transaction is rolled
367
430
  # back by the database due to a serialization failure.
368
431
  class SerializationFailure < TransactionRollbackError
@@ -409,12 +472,12 @@ module ActiveRecord
409
472
  #
410
473
  # For example, the following code would raise this exception:
411
474
  #
412
- # Post.order("length(title)").first
475
+ # Post.order("REPLACE(title, 'misc', 'zzzz') asc").pluck(:id)
413
476
  #
414
477
  # The desired result can be accomplished by wrapping the known-safe string
415
478
  # in Arel.sql:
416
479
  #
417
- # Post.order(Arel.sql("length(title)")).first
480
+ # Post.order(Arel.sql("REPLACE(title, 'misc', 'zzzz') asc")).pluck(:id)
418
481
  #
419
482
  # Again, such a workaround should *not* be used when passing user-provided
420
483
  # values, such as request parameters or model attributes to query methods.
@@ -41,7 +41,7 @@ module ActiveRecord
41
41
  @config_row ||= begin
42
42
  row = raw_rows.find { |fixture_name, _| fixture_name == "_fixture" }
43
43
  if row
44
- row.last
44
+ validate_config_row(row.last)
45
45
  else
46
46
  { 'model_class': nil, 'ignore': nil }
47
47
  end
@@ -58,6 +58,20 @@ module ActiveRecord
58
58
  end
59
59
  end
60
60
 
61
+ def validate_config_row(data)
62
+ unless Hash === data
63
+ raise Fixture::FormatError, "Invalid `_fixture` section: `_fixture` must be a hash: #{@file}"
64
+ end
65
+
66
+ begin
67
+ data.assert_valid_keys("model_class", "ignore")
68
+ rescue ArgumentError => error
69
+ raise Fixture::FormatError, "Invalid `_fixture` section: #{error.message}: #{@file}"
70
+ end
71
+
72
+ data
73
+ end
74
+
61
75
  # Validate our unmarshalled data.
62
76
  def validate(data)
63
77
  unless Hash === data || YAML::Omap === data
@@ -33,6 +33,33 @@ module ActiveRecord
33
33
  def join_table
34
34
  @association.through_reflection.table_name
35
35
  end
36
+
37
+ def timestamp_column_names
38
+ @association.through_reflection.klass.all_timestamp_attributes_in_model
39
+ end
40
+ end
41
+
42
+ class PrimaryKeyError < StandardError # :nodoc:
43
+ def initialize(label, association, value)
44
+ super(<<~MSG)
45
+ Unable to set #{association.name} to #{value} because the association has a
46
+ custom primary key (#{association.join_primary_key}) that does not match the
47
+ associated table's primary key (#{association.klass.primary_key}).
48
+
49
+ To fix this, change your fixture from
50
+
51
+ #{label}:
52
+ #{association.name}: #{value}
53
+
54
+ to
55
+
56
+ #{label}:
57
+ #{association.foreign_key}: **value**
58
+
59
+ where **value** is the #{association.join_primary_key} value for the
60
+ associated #{association.klass.name} record.
61
+ MSG
62
+ end
36
63
  end
37
64
 
38
65
  def initialize(fixture, table_rows:, label:, now:)
@@ -115,9 +142,13 @@ module ActiveRecord
115
142
  fk_name = association.join_foreign_key
116
143
 
117
144
  if association.name.to_s != fk_name && value = @row.delete(association.name.to_s)
118
- if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
119
- # support polymorphic belongs_to as "label (Type)"
120
- @row[association.join_foreign_type] = $1
145
+ if association.polymorphic?
146
+ if value.sub!(/\s*\(([^)]*)\)\s*$/, "")
147
+ # support polymorphic belongs_to as "label (Type)"
148
+ @row[association.join_foreign_type] = $1
149
+ end
150
+ elsif association.join_primary_key != association.klass.primary_key
151
+ raise PrimaryKeyError.new(@label, association, value)
121
152
  end
122
153
 
123
154
  fk_type = reflection_class.type_for_attribute(fk_name).type
@@ -141,8 +172,12 @@ module ActiveRecord
141
172
 
142
173
  targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
143
174
  joins = targets.map do |target|
144
- { lhs_key => @row[model_metadata.primary_key_name],
145
- rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
175
+ join = { lhs_key => @row[model_metadata.primary_key_name],
176
+ rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
177
+ association.timestamp_column_names.each do |col|
178
+ join[col] = @now
179
+ end
180
+ join
146
181
  end
147
182
  @table_rows.tables[table_name].concat(joins)
148
183
  end
@@ -6,7 +6,7 @@ require "active_record/fixture_set/model_metadata"
6
6
  module ActiveRecord
7
7
  class FixtureSet
8
8
  class TableRows # :nodoc:
9
- def initialize(table_name, model_class:, fixtures:, config:)
9
+ def initialize(table_name, model_class:, fixtures:)
10
10
  @model_class = model_class
11
11
 
12
12
  # track any join tables we need to insert later
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  # ensure this table is loaded before any HABTM associations
16
16
  @tables[table_name] = nil
17
17
 
18
- build_table_rows_from(table_name, fixtures, config)
18
+ build_table_rows_from(table_name, fixtures)
19
19
  end
20
20
 
21
21
  attr_reader :tables, :model_class
@@ -29,8 +29,8 @@ module ActiveRecord
29
29
  end
30
30
 
31
31
  private
32
- def build_table_rows_from(table_name, fixtures, config)
33
- now = config.default_timezone == :utc ? Time.now.utc : Time.now
32
+ def build_table_rows_from(table_name, fixtures)
33
+ now = ActiveRecord.default_timezone == :utc ? Time.now.utc : Time.now
34
34
 
35
35
  @tables[table_name] = fixtures.map do |label, fixture|
36
36
  TableRow.new(
@@ -12,7 +12,7 @@ require "active_record/fixture_set/table_rows"
12
12
  require "active_record/test_fixtures"
13
13
 
14
14
  module ActiveRecord
15
- class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
15
+ class FixtureClassNotFound < ActiveRecord::ActiveRecordError # :nodoc:
16
16
  end
17
17
 
18
18
  # \Fixtures are a way of organizing data that you want to test against; in short, sample data.
@@ -35,7 +35,7 @@ module ActiveRecord
35
35
  # name: Google
36
36
  # url: http://www.google.com
37
37
  #
38
- # This fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and
38
+ # This fixture file includes two fixtures. Each YAML fixture (i.e. record) is given a name and
39
39
  # is followed by an indented list of key/value pairs in the "key: value" format. Records are
40
40
  # separated by a blank line for your viewing pleasure.
41
41
  #
@@ -152,7 +152,7 @@ module ActiveRecord
152
152
  # - define a helper method in <tt>test_helper.rb</tt>
153
153
  # module FixtureFileHelpers
154
154
  # def file_sha(path)
155
- # Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
155
+ # OpenSSL::Digest::SHA256.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
156
156
  # end
157
157
  # end
158
158
  # ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers
@@ -311,7 +311,7 @@ module ActiveRecord
311
311
  #
312
312
  # Just provide the polymorphic target type and Active Record will take care of the rest.
313
313
  #
314
- # === has_and_belongs_to_many
314
+ # === has_and_belongs_to_many or has_many :through
315
315
  #
316
316
  # Time to give our monkey some fruit.
317
317
  #
@@ -426,7 +426,7 @@ module ActiveRecord
426
426
  # _fixture:
427
427
  # ignore:
428
428
  # - base
429
- # # or use "ignore: base" when there is only one fixture needs to be ignored.
429
+ # # or use "ignore: base" when there is only one fixture that needs to be ignored.
430
430
  #
431
431
  # base: &base
432
432
  # admin: false
@@ -637,6 +637,10 @@ module ActiveRecord
637
637
 
638
638
  conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
639
639
 
640
+ if ActiveRecord.verify_foreign_keys_for_fixtures && !conn.all_foreign_keys_valid?
641
+ raise "Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations."
642
+ end
643
+
640
644
  # Cap primary key sequences to max(pk).
641
645
  if conn.respond_to?(:reset_pk_sequence!)
642
646
  set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
@@ -689,7 +693,6 @@ module ActiveRecord
689
693
  table_name,
690
694
  model_class: model_class,
691
695
  fixtures: fixtures,
692
- config: config,
693
696
  ).to_hash
694
697
  end
695
698
 
@@ -741,13 +744,13 @@ module ActiveRecord
741
744
  end
742
745
  end
743
746
 
744
- class Fixture #:nodoc:
747
+ class Fixture # :nodoc:
745
748
  include Enumerable
746
749
 
747
- class FixtureError < StandardError #:nodoc:
750
+ class FixtureError < StandardError # :nodoc:
748
751
  end
749
752
 
750
- class FormatError < FixtureError #:nodoc:
753
+ class FormatError < FixtureError # :nodoc:
751
754
  end
752
755
 
753
756
  attr_reader :model_class, :fixture
@@ -761,8 +764,8 @@ module ActiveRecord
761
764
  model_class.name if model_class
762
765
  end
763
766
 
764
- def each
765
- fixture.each { |item| yield item }
767
+ def each(&block)
768
+ fixture.each(&block)
766
769
  end
767
770
 
768
771
  def [](key)
@@ -782,3 +785,5 @@ module ActiveRecord
782
785
  end
783
786
  end
784
787
  end
788
+
789
+ ActiveSupport.run_load_hooks :active_record_fixture_set, ActiveRecord::FixtureSet
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class FutureResult # :nodoc:
5
+ class EventBuffer
6
+ def initialize(future_result, instrumenter)
7
+ @future_result = future_result
8
+ @instrumenter = instrumenter
9
+ @events = []
10
+ end
11
+
12
+ def instrument(name, payload = {}, &block)
13
+ event = @instrumenter.new_event(name, payload)
14
+ @events << event
15
+ event.record(&block)
16
+ end
17
+
18
+ def flush
19
+ events, @events = @events, []
20
+ events.each do |event|
21
+ event.payload[:lock_wait] = @future_result.lock_wait
22
+ ActiveSupport::Notifications.publish_event(event)
23
+ end
24
+ end
25
+ end
26
+
27
+ Canceled = Class.new(ActiveRecordError)
28
+
29
+ delegate :empty?, :to_a, to: :result
30
+
31
+ attr_reader :lock_wait
32
+
33
+ def initialize(pool, *args, **kwargs)
34
+ @mutex = Mutex.new
35
+
36
+ @session = nil
37
+ @pool = pool
38
+ @args = args
39
+ @kwargs = kwargs
40
+
41
+ @pending = true
42
+ @error = nil
43
+ @result = nil
44
+ @instrumenter = ActiveSupport::Notifications.instrumenter
45
+ @event_buffer = nil
46
+ end
47
+
48
+ def schedule!(session)
49
+ @session = session
50
+ @pool.schedule_query(self)
51
+ end
52
+
53
+ def execute!(connection)
54
+ execute_query(connection)
55
+ end
56
+
57
+ def cancel
58
+ @pending = false
59
+ @error = Canceled
60
+ self
61
+ end
62
+
63
+ def execute_or_skip
64
+ return unless pending?
65
+
66
+ @pool.with_connection do |connection|
67
+ return unless @mutex.try_lock
68
+ begin
69
+ if pending?
70
+ @event_buffer = EventBuffer.new(self, @instrumenter)
71
+ connection.with_instrumenter(@event_buffer) do
72
+ execute_query(connection, async: true)
73
+ end
74
+ end
75
+ ensure
76
+ @mutex.unlock
77
+ end
78
+ end
79
+ end
80
+
81
+ def result
82
+ execute_or_wait
83
+ @event_buffer&.flush
84
+
85
+ if canceled?
86
+ raise Canceled
87
+ elsif @error
88
+ raise @error
89
+ else
90
+ @result
91
+ end
92
+ end
93
+
94
+ def pending?
95
+ @pending && (!@session || @session.active?)
96
+ end
97
+
98
+ private
99
+ def canceled?
100
+ @session && !@session.active?
101
+ end
102
+
103
+ def execute_or_wait
104
+ if pending?
105
+ start = Concurrent.monotonic_time
106
+ @mutex.synchronize do
107
+ if pending?
108
+ execute_query(@pool.connection)
109
+ else
110
+ @lock_wait = (Concurrent.monotonic_time - start) * 1_000
111
+ end
112
+ end
113
+ else
114
+ @lock_wait = 0.0
115
+ end
116
+ end
117
+
118
+ def execute_query(connection, async: false)
119
+ @result = exec_query(connection, *@args, **@kwargs, async: async)
120
+ rescue => error
121
+ @error = error
122
+ ensure
123
+ @pending = false
124
+ end
125
+
126
+ def exec_query(connection, *args, **kwargs)
127
+ connection.exec_query(*args, **kwargs)
128
+ end
129
+
130
+ class SelectAll < FutureResult # :nodoc:
131
+ private
132
+ def exec_query(*, **)
133
+ super
134
+ rescue ::RangeError
135
+ ActiveRecord::Result.empty
136
+ end
137
+ end
138
+ end
139
+ end
@@ -7,10 +7,10 @@ module ActiveRecord
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 6
11
- MINOR = 1
12
- TINY = 7
13
- PRE = "7"
10
+ MAJOR = 7
11
+ MINOR = 0
12
+ TINY = 0
13
+ PRE = "alpha1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/inflector"
3
4
  require "active_support/core_ext/hash/indifferent_access"
4
5
 
5
6
  module ActiveRecord
@@ -43,6 +44,8 @@ module ActiveRecord
43
44
  # Determines whether to store the full constant name including namespace when using STI.
44
45
  # This is true, by default.
45
46
  class_attribute :store_full_sti_class, instance_writer: false, default: true
47
+
48
+ set_base_class
46
49
  end
47
50
 
48
51
  module ClassMethods
@@ -85,7 +88,7 @@ module ActiveRecord
85
88
  end
86
89
  end
87
90
 
88
- def finder_needs_type_condition? #:nodoc:
91
+ def finder_needs_type_condition? # :nodoc:
89
92
  # This is like this because benchmarking justifies the strange :false stuff
90
93
  :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
91
94
  end
@@ -98,17 +101,7 @@ module ActiveRecord
98
101
  #
99
102
  # If B < A and C < B and if A is an abstract_class then both B.base_class
100
103
  # and C.base_class would return B as the answer since A is an abstract_class.
101
- def base_class
102
- unless self < Base
103
- raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
104
- end
105
-
106
- if superclass == Base || superclass.abstract_class?
107
- self
108
- else
109
- superclass.base_class
110
- end
111
- end
104
+ attr_reader :base_class
112
105
 
113
106
  # Returns whether the class is a base class.
114
107
  # See #base_class for more information.
@@ -164,6 +157,21 @@ module ActiveRecord
164
157
  defined?(@abstract_class) && @abstract_class == true
165
158
  end
166
159
 
160
+ # Sets the application record class for Active Record
161
+ #
162
+ # This is useful if your application uses a different class than
163
+ # ApplicationRecord for your primary abstract class. This class
164
+ # will share a database connection with Active Record. It is the class
165
+ # that connects to your primary database.
166
+ def primary_abstract_class
167
+ if ActiveRecord.application_record_class && ActiveRecord.application_record_class.name != name
168
+ raise ArgumentError, "The `primary_abstract_class` is already set to #{ActiveRecord.application_record_class.inspect}. There can only be one `primary_abstract_class` in an application."
169
+ end
170
+
171
+ self.abstract_class = true
172
+ ActiveRecord.application_record_class = self
173
+ end
174
+
167
175
  # Returns the value to be stored in the inheritance column for STI.
168
176
  def sti_name
169
177
  store_full_sti_class && store_full_class_name ? name : name.demodulize
@@ -174,7 +182,7 @@ module ActiveRecord
174
182
  # It is used to find the class correspondent to the value stored in the inheritance column.
175
183
  def sti_class_for(type_name)
176
184
  if store_full_sti_class && store_full_class_name
177
- ActiveSupport::Dependencies.constantize(type_name)
185
+ type_name.constantize
178
186
  else
179
187
  compute_type(type_name)
180
188
  end
@@ -196,17 +204,31 @@ module ActiveRecord
196
204
  # It is used to find the class correspondent to the value stored in the polymorphic type column.
197
205
  def polymorphic_class_for(name)
198
206
  if store_full_class_name
199
- ActiveSupport::Dependencies.constantize(name)
207
+ name.constantize
200
208
  else
201
209
  compute_type(name)
202
210
  end
203
211
  end
204
212
 
205
213
  def inherited(subclass)
214
+ subclass.set_base_class
206
215
  subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
207
216
  super
208
217
  end
209
218
 
219
+ def dup # :nodoc:
220
+ # `initialize_dup` / `initialize_copy` don't work when defined
221
+ # in the `singleton_class`.
222
+ other = super
223
+ other.set_base_class
224
+ other
225
+ end
226
+
227
+ def initialize_clone(other) # :nodoc:
228
+ super
229
+ set_base_class
230
+ end
231
+
210
232
  protected
211
233
  # Returns the class type of the record using the current module as a prefix. So descendants of
212
234
  # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
@@ -214,10 +236,10 @@ module ActiveRecord
214
236
  if type_name.start_with?("::")
215
237
  # If the type is prefixed with a scope operator then we assume that
216
238
  # the type_name is an absolute reference.
217
- ActiveSupport::Dependencies.constantize(type_name)
239
+ type_name.constantize
218
240
  else
219
241
  type_candidate = @_type_candidates_cache[type_name]
220
- if type_candidate && type_constant = ActiveSupport::Dependencies.safe_constantize(type_candidate)
242
+ if type_candidate && type_constant = type_candidate.safe_constantize
221
243
  return type_constant
222
244
  end
223
245
 
@@ -227,7 +249,7 @@ module ActiveRecord
227
249
  candidates << type_name
228
250
 
229
251
  candidates.each do |candidate|
230
- constant = ActiveSupport::Dependencies.safe_constantize(candidate)
252
+ constant = candidate.safe_constantize
231
253
  if candidate == constant.to_s
232
254
  @_type_candidates_cache[type_name] = candidate
233
255
  return constant
@@ -238,6 +260,22 @@ module ActiveRecord
238
260
  end
239
261
  end
240
262
 
263
+ def set_base_class # :nodoc:
264
+ @base_class = if self == Base
265
+ self
266
+ else
267
+ unless self < Base
268
+ raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
269
+ end
270
+
271
+ if superclass == Base || superclass.abstract_class?
272
+ self
273
+ else
274
+ superclass.base_class
275
+ end
276
+ end
277
+ end
278
+
241
279
  private
242
280
  # Called by +instantiate+ to decide which class to use for a new
243
281
  # record instance. For single-table inheritance, we check the record