activerecord 6.1.6 → 7.0.4

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 (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1314 -975
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/aggregations.rb +1 -1
  5. data/lib/active_record/association_relation.rb +0 -10
  6. data/lib/active_record/associations/association.rb +33 -17
  7. data/lib/active_record/associations/association_scope.rb +1 -3
  8. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  10. data/lib/active_record/associations/builder/association.rb +8 -2
  11. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  12. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  13. data/lib/active_record/associations/builder/has_many.rb +3 -2
  14. data/lib/active_record/associations/builder/has_one.rb +2 -1
  15. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  16. data/lib/active_record/associations/collection_association.rb +19 -21
  17. data/lib/active_record/associations/collection_proxy.rb +10 -5
  18. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  19. data/lib/active_record/associations/has_many_association.rb +8 -5
  20. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  21. data/lib/active_record/associations/has_one_association.rb +10 -7
  22. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency.rb +23 -15
  24. data/lib/active_record/associations/preloader/association.rb +186 -52
  25. data/lib/active_record/associations/preloader/batch.rb +48 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +49 -13
  28. data/lib/active_record/associations/preloader.rb +39 -113
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +3 -3
  31. data/lib/active_record/associations.rb +124 -95
  32. data/lib/active_record/asynchronous_queries_tracker.rb +60 -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 +49 -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 +57 -19
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +14 -15
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +8 -23
  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 +10 -2
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -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 +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +38 -13
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -24
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +105 -81
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +37 -21
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  68. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  69. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  75. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  80. data/lib/active_record/connection_adapters/postgresql/quoting.rb +51 -51
  81. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +37 -19
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +208 -107
  87. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  88. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  89. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +96 -32
  92. data/lib/active_record/connection_adapters.rb +6 -5
  93. data/lib/active_record/connection_handling.rb +49 -55
  94. data/lib/active_record/core.rb +124 -134
  95. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  96. data/lib/active_record/database_configurations/database_config.rb +12 -9
  97. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  98. data/lib/active_record/database_configurations/url_config.rb +2 -2
  99. data/lib/active_record/database_configurations.rb +15 -32
  100. data/lib/active_record/delegated_type.rb +53 -12
  101. data/lib/active_record/destroy_association_async_job.rb +1 -1
  102. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  103. data/lib/active_record/dynamic_matchers.rb +1 -1
  104. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  105. data/lib/active_record/encryption/cipher.rb +53 -0
  106. data/lib/active_record/encryption/config.rb +44 -0
  107. data/lib/active_record/encryption/configurable.rb +67 -0
  108. data/lib/active_record/encryption/context.rb +35 -0
  109. data/lib/active_record/encryption/contexts.rb +72 -0
  110. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  111. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  112. data/lib/active_record/encryption/encryptable_record.rb +206 -0
  113. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  114. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  115. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  116. data/lib/active_record/encryption/encryptor.rb +155 -0
  117. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  118. data/lib/active_record/encryption/errors.rb +15 -0
  119. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  120. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  121. data/lib/active_record/encryption/key.rb +28 -0
  122. data/lib/active_record/encryption/key_generator.rb +42 -0
  123. data/lib/active_record/encryption/key_provider.rb +46 -0
  124. data/lib/active_record/encryption/message.rb +33 -0
  125. data/lib/active_record/encryption/message_serializer.rb +90 -0
  126. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  127. data/lib/active_record/encryption/properties.rb +76 -0
  128. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  129. data/lib/active_record/encryption/scheme.rb +99 -0
  130. data/lib/active_record/encryption.rb +55 -0
  131. data/lib/active_record/enum.rb +50 -43
  132. data/lib/active_record/errors.rb +67 -4
  133. data/lib/active_record/explain_registry.rb +11 -6
  134. data/lib/active_record/fixture_set/file.rb +15 -1
  135. data/lib/active_record/fixture_set/table_row.rb +41 -6
  136. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  137. data/lib/active_record/fixtures.rb +20 -23
  138. data/lib/active_record/future_result.rb +139 -0
  139. data/lib/active_record/gem_version.rb +4 -4
  140. data/lib/active_record/inheritance.rb +55 -17
  141. data/lib/active_record/insert_all.rb +80 -14
  142. data/lib/active_record/integration.rb +4 -3
  143. data/lib/active_record/internal_metadata.rb +1 -5
  144. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  145. data/lib/active_record/locking/optimistic.rb +10 -9
  146. data/lib/active_record/locking/pessimistic.rb +10 -4
  147. data/lib/active_record/log_subscriber.rb +23 -7
  148. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  149. data/lib/active_record/middleware/database_selector.rb +18 -6
  150. data/lib/active_record/middleware/shard_selector.rb +60 -0
  151. data/lib/active_record/migration/command_recorder.rb +7 -7
  152. data/lib/active_record/migration/compatibility.rb +84 -2
  153. data/lib/active_record/migration/join_table.rb +1 -1
  154. data/lib/active_record/migration.rb +114 -83
  155. data/lib/active_record/model_schema.rb +58 -59
  156. data/lib/active_record/nested_attributes.rb +13 -12
  157. data/lib/active_record/no_touching.rb +3 -3
  158. data/lib/active_record/null_relation.rb +2 -6
  159. data/lib/active_record/persistence.rb +228 -60
  160. data/lib/active_record/query_cache.rb +2 -2
  161. data/lib/active_record/query_logs.rb +138 -0
  162. data/lib/active_record/querying.rb +16 -6
  163. data/lib/active_record/railtie.rb +136 -22
  164. data/lib/active_record/railties/controller_runtime.rb +1 -1
  165. data/lib/active_record/railties/databases.rake +78 -136
  166. data/lib/active_record/readonly_attributes.rb +11 -0
  167. data/lib/active_record/reflection.rb +73 -50
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  169. data/lib/active_record/relation/batches.rb +6 -6
  170. data/lib/active_record/relation/calculations.rb +43 -38
  171. data/lib/active_record/relation/delegation.rb +7 -7
  172. data/lib/active_record/relation/finder_methods.rb +31 -35
  173. data/lib/active_record/relation/merger.rb +20 -13
  174. data/lib/active_record/relation/predicate_builder.rb +1 -6
  175. data/lib/active_record/relation/query_attribute.rb +5 -11
  176. data/lib/active_record/relation/query_methods.rb +276 -67
  177. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  178. data/lib/active_record/relation/spawn_methods.rb +2 -2
  179. data/lib/active_record/relation/where_clause.rb +10 -19
  180. data/lib/active_record/relation.rb +189 -88
  181. data/lib/active_record/result.rb +17 -7
  182. data/lib/active_record/runtime_registry.rb +9 -13
  183. data/lib/active_record/sanitization.rb +17 -12
  184. data/lib/active_record/schema.rb +38 -23
  185. data/lib/active_record/schema_dumper.rb +25 -19
  186. data/lib/active_record/schema_migration.rb +4 -4
  187. data/lib/active_record/scoping/default.rb +60 -13
  188. data/lib/active_record/scoping/named.rb +3 -11
  189. data/lib/active_record/scoping.rb +64 -34
  190. data/lib/active_record/serialization.rb +6 -1
  191. data/lib/active_record/signed_id.rb +3 -3
  192. data/lib/active_record/store.rb +7 -2
  193. data/lib/active_record/suppressor.rb +11 -15
  194. data/lib/active_record/tasks/database_tasks.rb +127 -60
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  197. data/lib/active_record/test_databases.rb +1 -1
  198. data/lib/active_record/test_fixtures.rb +16 -9
  199. data/lib/active_record/timestamp.rb +3 -4
  200. data/lib/active_record/transactions.rb +9 -14
  201. data/lib/active_record/translation.rb +3 -3
  202. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  203. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  204. data/lib/active_record/type/internal/timezone.rb +2 -2
  205. data/lib/active_record/type/serialized.rb +1 -1
  206. data/lib/active_record/type/type_map.rb +17 -20
  207. data/lib/active_record/type.rb +1 -2
  208. data/lib/active_record/validations/associated.rb +4 -4
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +4 -4
  211. data/lib/active_record/version.rb +1 -1
  212. data/lib/active_record.rb +217 -27
  213. data/lib/arel/attributes/attribute.rb +0 -8
  214. data/lib/arel/crud.rb +28 -22
  215. data/lib/arel/delete_manager.rb +18 -4
  216. data/lib/arel/filter_predications.rb +9 -0
  217. data/lib/arel/insert_manager.rb +2 -3
  218. data/lib/arel/nodes/casted.rb +1 -1
  219. data/lib/arel/nodes/delete_statement.rb +12 -13
  220. data/lib/arel/nodes/filter.rb +10 -0
  221. data/lib/arel/nodes/function.rb +1 -0
  222. data/lib/arel/nodes/insert_statement.rb +2 -2
  223. data/lib/arel/nodes/select_core.rb +2 -2
  224. data/lib/arel/nodes/select_statement.rb +2 -2
  225. data/lib/arel/nodes/update_statement.rb +8 -3
  226. data/lib/arel/nodes.rb +1 -0
  227. data/lib/arel/predications.rb +11 -3
  228. data/lib/arel/select_manager.rb +10 -4
  229. data/lib/arel/table.rb +0 -1
  230. data/lib/arel/tree_manager.rb +0 -12
  231. data/lib/arel/update_manager.rb +18 -4
  232. data/lib/arel/visitors/dot.rb +80 -90
  233. data/lib/arel/visitors/mysql.rb +8 -2
  234. data/lib/arel/visitors/postgresql.rb +0 -10
  235. data/lib/arel/visitors/to_sql.rb +58 -2
  236. data/lib/arel.rb +2 -1
  237. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  238. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  239. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  240. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  241. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  242. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  243. metadata +55 -11
@@ -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:)
@@ -99,7 +126,7 @@ module ActiveRecord
99
126
  end
100
127
 
101
128
  def resolve_enums
102
- model_class.defined_enums.each do |name, values|
129
+ reflection_class.defined_enums.each do |name, values|
103
130
  if @row.include?(name)
104
131
  @row[name] = values.fetch(@row[name], @row[name])
105
132
  end
@@ -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
@@ -241,13 +241,13 @@ module ActiveRecord
241
241
  # The generated ID for a given label is constant, so we can discover
242
242
  # any fixture's ID without loading anything, as long as we know the label.
243
243
  #
244
- # == Label references for associations (belongs_to, has_one, has_many)
244
+ # == Label references for associations (+belongs_to+, +has_one+, +has_many+)
245
245
  #
246
246
  # Specifying foreign keys in fixtures can be very fragile, not to
247
247
  # mention difficult to read. Since Active Record can figure out the ID of
248
248
  # any fixture from its label, you can specify FK's by label instead of ID.
249
249
  #
250
- # === belongs_to
250
+ # === +belongs_to+
251
251
  #
252
252
  # Let's break out some more monkeys and pirates.
253
253
  #
@@ -286,7 +286,7 @@ module ActiveRecord
286
286
  # a target *label* for the *association* (monkey: george) rather than
287
287
  # a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
288
288
  #
289
- # ==== Polymorphic belongs_to
289
+ # ==== Polymorphic +belongs_to+
290
290
  #
291
291
  # Supporting polymorphic relationships is a little bit more complicated, since
292
292
  # Active Record needs to know what type your association is pointing at. Something
@@ -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 <tt>has_many :through</tt>
315
315
  #
316
316
  # Time to give our monkey some fruit.
317
317
  #
@@ -407,7 +407,7 @@ module ActiveRecord
407
407
  # defaults:
408
408
  #
409
409
  # DEFAULTS: &DEFAULTS
410
- # created_on: <%= 3.weeks.ago.to_s(:db) %>
410
+ # created_on: <%= 3.weeks.ago.to_fs(:db) %>
411
411
  #
412
412
  # first:
413
413
  # name: Smurf
@@ -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
@@ -585,14 +585,6 @@ module ActiveRecord
585
585
  end
586
586
  end
587
587
 
588
- def signed_global_id(fixture_set_name, label, column_type: :integer, **options)
589
- identifier = identify(label, column_type)
590
- model_name = default_fixture_model_name(fixture_set_name)
591
- uri = URI::GID.build([GlobalID.app, model_name, identifier, {}])
592
-
593
- SignedGlobalID.new(uri, **options)
594
- end
595
-
596
588
  # Superclass for the evaluation contexts used by ERB fixtures.
597
589
  def context_class
598
590
  @context_class ||= Class.new
@@ -637,6 +629,10 @@ module ActiveRecord
637
629
 
638
630
  conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
639
631
 
632
+ if ActiveRecord.verify_foreign_keys_for_fixtures && !conn.all_foreign_keys_valid?
633
+ raise "Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations."
634
+ end
635
+
640
636
  # Cap primary key sequences to max(pk).
641
637
  if conn.respond_to?(:reset_pk_sequence!)
642
638
  set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
@@ -689,7 +685,6 @@ module ActiveRecord
689
685
  table_name,
690
686
  model_class: model_class,
691
687
  fixtures: fixtures,
692
- config: config,
693
688
  ).to_hash
694
689
  end
695
690
 
@@ -741,13 +736,13 @@ module ActiveRecord
741
736
  end
742
737
  end
743
738
 
744
- class Fixture #:nodoc:
739
+ class Fixture # :nodoc:
745
740
  include Enumerable
746
741
 
747
- class FixtureError < StandardError #:nodoc:
742
+ class FixtureError < StandardError # :nodoc:
748
743
  end
749
744
 
750
- class FormatError < FixtureError #:nodoc:
745
+ class FormatError < FixtureError # :nodoc:
751
746
  end
752
747
 
753
748
  attr_reader :model_class, :fixture
@@ -761,8 +756,8 @@ module ActiveRecord
761
756
  model_class.name if model_class
762
757
  end
763
758
 
764
- def each
765
- fixture.each { |item| yield item }
759
+ def each(&block)
760
+ fixture.each(&block)
766
761
  end
767
762
 
768
763
  def [](key)
@@ -782,3 +777,5 @@ module ActiveRecord
782
777
  end
783
778
  end
784
779
  end
780
+
781
+ 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 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
106
+ @mutex.synchronize do
107
+ if pending?
108
+ execute_query(@pool.connection)
109
+ else
110
+ @lock_wait = (Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start)
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
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- # Returns the version of the currently loaded Active Record as a <tt>Gem::Version</tt>
4
+ # Returns the currently loaded version of Active Record as a <tt>Gem::Version</tt>.
5
5
  def self.gem_version
6
6
  Gem::Version.new VERSION::STRING
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 6
11
- MINOR = 1
12
- TINY = 6
10
+ MAJOR = 7
11
+ MINOR = 0
12
+ TINY = 4
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -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