activerecord 6.1.7 → 7.1.5

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 (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +51 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +39 -35
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. data/lib/active_record/null_relation.rb +0 -67
@@ -1,42 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/enumerable"
4
- require "active_support/core_ext/hash/indifferent_access"
5
- require "active_support/core_ext/string/filters"
4
+ require "active_support/core_ext/module/delegation"
6
5
  require "active_support/parameter_filter"
7
6
  require "concurrent/map"
8
7
 
9
8
  module ActiveRecord
9
+ # = Active Record \Core
10
10
  module Core
11
11
  extend ActiveSupport::Concern
12
+ include ActiveModel::Access
12
13
 
13
14
  included do
14
15
  ##
15
16
  # :singleton-method:
16
17
  #
17
- # Accepts a logger conforming to the interface of Log4r which is then
18
- # passed on to any new database connections made and which can be
19
- # retrieved on both a class and instance level by calling +logger+.
20
- mattr_accessor :logger, instance_writer: false
21
-
22
- ##
23
- # :singleton-method:
24
- #
25
- # Specifies if the methods calling database queries should be logged below
26
- # their relevant queries. Defaults to false.
27
- mattr_accessor :verbose_query_logs, instance_writer: false, default: false
18
+ # Accepts a logger conforming to the interface of Log4r or the default
19
+ # Ruby +Logger+ class, which is then passed on to any new database
20
+ # connections made. You can retrieve this logger by calling +logger+ on
21
+ # either an Active Record model class or an Active Record model instance.
22
+ class_attribute :logger, instance_writer: false
23
+
24
+ class_attribute :_destroy_association_async_job, instance_accessor: false, default: "ActiveRecord::DestroyAssociationAsyncJob"
25
+
26
+ # The job class used to destroy associations in the background.
27
+ def self.destroy_association_async_job
28
+ if _destroy_association_async_job.is_a?(String)
29
+ self._destroy_association_async_job = _destroy_association_async_job.constantize
30
+ end
31
+ _destroy_association_async_job
32
+ rescue NameError => error
33
+ raise NameError, "Unable to load destroy_association_async_job: #{error.message}"
34
+ end
28
35
 
29
- ##
30
- # :singleton-method:
31
- #
32
- # Specifies the names of the queues used by background jobs.
33
- mattr_accessor :queues, instance_accessor: false, default: {}
36
+ singleton_class.alias_method :destroy_association_async_job=, :_destroy_association_async_job=
37
+ delegate :destroy_association_async_job, to: :class
34
38
 
35
39
  ##
36
40
  # :singleton-method:
37
41
  #
38
- # Specifies the job used to destroy associations in the background
39
- class_attribute :destroy_association_async_job, instance_writer: false, instance_predicate: false, default: false
42
+ # Specifies the maximum number of records that will be destroyed in a
43
+ # single background job by the <tt>dependent: :destroy_async</tt>
44
+ # association option. When +nil+ (default), all dependent records will be
45
+ # destroyed in a single background job. If specified, the records to be
46
+ # destroyed will be split into multiple background jobs.
47
+ class_attribute :destroy_association_async_batch_size, instance_writer: false, instance_predicate: false, default: nil
40
48
 
41
49
  ##
42
50
  # Contains the database configuration - as is typically stored in config/database.yml -
@@ -46,19 +54,19 @@ module ActiveRecord
46
54
  #
47
55
  # development:
48
56
  # adapter: sqlite3
49
- # database: db/development.sqlite3
57
+ # database: storage/development.sqlite3
50
58
  #
51
59
  # production:
52
60
  # adapter: sqlite3
53
- # database: db/production.sqlite3
61
+ # database: storage/production.sqlite3
54
62
  #
55
63
  # ...would result in ActiveRecord::Base.configurations to look like this:
56
64
  #
57
65
  # #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
58
66
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
59
- # @name="primary", @config={adapter: "sqlite3", database: "db/development.sqlite3"}>,
67
+ # @name="primary", @config={adapter: "sqlite3", database: "storage/development.sqlite3"}>,
60
68
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
61
- # @name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
69
+ # @name="primary", @config={adapter: "sqlite3", database: "storage/production.sqlite3"}>
62
70
  # ]>
63
71
  def self.configurations=(config)
64
72
  @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
@@ -72,80 +80,19 @@ module ActiveRecord
72
80
 
73
81
  ##
74
82
  # :singleton-method:
75
- # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
76
- # dates and times from the database. This is set to :utc by default.
77
- mattr_accessor :default_timezone, instance_writer: false, default: :utc
78
-
79
- ##
80
- # :singleton-method:
81
- # Specifies the format to use when dumping the database schema with Rails'
82
- # Rakefile. If :sql, the schema is dumped as (potentially database-
83
- # specific) SQL statements. If :ruby, the schema is dumped as an
84
- # ActiveRecord::Schema file which can be loaded into any database that
85
- # supports migrations. Use :ruby if you want to have different database
86
- # adapters for, e.g., your development and test environments.
87
- mattr_accessor :schema_format, instance_writer: false, default: :ruby
88
-
89
- ##
90
- # :singleton-method:
91
- # Specifies if an error should be raised if the query has an order being
92
- # ignored when doing batch queries. Useful in applications where the
93
- # scope being ignored is error-worthy, rather than a warning.
94
- mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
95
-
96
- ##
97
- # :singleton-method:
98
- # Specify whether or not to use timestamps for migration versions
99
- mattr_accessor :timestamped_migrations, instance_writer: false, default: true
100
-
101
- ##
102
- # :singleton-method:
103
- # Specify whether schema dump should happen at the end of the
104
- # db:migrate rails command. This is true by default, which is useful for the
105
- # development environment. This should ideally be false in the production
106
- # environment where dumping schema is rarely needed.
107
- mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
108
-
109
- ##
110
- # :singleton-method:
111
- # Specifies which database schemas to dump when calling db:schema:dump.
112
- # If the value is :schema_search_path (the default), any schemas listed in
113
- # schema_search_path are dumped. Use :all to dump all schemas regardless
114
- # of schema_search_path, or a string of comma separated schemas for a
115
- # custom list.
116
- mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
117
-
118
- ##
119
- # :singleton-method:
120
- # Specify a threshold for the size of query result sets. If the number of
121
- # records in the set exceeds the threshold, a warning is logged. This can
122
- # be used to identify queries which load thousands of records and
123
- # potentially cause memory bloat.
124
- mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
125
-
126
- ##
127
- # :singleton-method:
128
- # Show a warning when Rails couldn't parse your database.yml
129
- # for multiple databases.
130
- mattr_accessor :suppress_multiple_database_warning, instance_writer: false, default: false
131
-
132
- mattr_accessor :maintain_test_schema, instance_accessor: false
83
+ # Force enumeration of all columns in SELECT statements.
84
+ # e.g. <tt>SELECT first_name, last_name FROM ...</tt> instead of <tt>SELECT * FROM ...</tt>
85
+ # This avoids +PreparedStatementCacheExpired+ errors when a column is added
86
+ # to the database while the app is running.
87
+ class_attribute :enumerate_columns_in_select_statements, instance_accessor: false, default: false
133
88
 
134
89
  class_attribute :belongs_to_required_by_default, instance_accessor: false
135
90
 
136
- ##
137
- # :singleton-method:
138
- # Set the application to log or raise when an association violates strict loading.
139
- # Defaults to :raise.
140
- mattr_accessor :action_on_strict_loading_violation, instance_accessor: false, default: :raise
141
-
142
91
  class_attribute :strict_loading_by_default, instance_accessor: false, default: false
143
92
 
144
- mattr_accessor :writing_role, instance_accessor: false, default: :writing
145
-
146
- mattr_accessor :reading_role, instance_accessor: false, default: :reading
93
+ class_attribute :has_many_inversing, instance_accessor: false, default: false
147
94
 
148
- mattr_accessor :has_many_inversing, instance_accessor: false, default: false
95
+ class_attribute :run_commit_callbacks_on_first_saved_instances_in_transaction, instance_accessor: false, default: true
149
96
 
150
97
  class_attribute :default_connection_handler, instance_writer: false
151
98
 
@@ -153,40 +100,35 @@ module ActiveRecord
153
100
 
154
101
  class_attribute :default_shard, instance_writer: false
155
102
 
156
- mattr_accessor :legacy_connection_handling, instance_writer: false, default: true
103
+ class_attribute :shard_selector, instance_accessor: false, default: nil
157
104
 
158
- # Application configurable boolean that instructs the YAML Coder to use
159
- # an unsafe load if set to true.
160
- mattr_accessor :use_yaml_unsafe_load, instance_writer: false, default: false
161
-
162
- # Application configurable array that provides additional permitted classes
163
- # to Psych safe_load in the YAML Coder
164
- mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: [Symbol]
105
+ def self.application_record_class? # :nodoc:
106
+ if ActiveRecord.application_record_class
107
+ self == ActiveRecord.application_record_class
108
+ else
109
+ if defined?(ApplicationRecord) && self == ApplicationRecord
110
+ true
111
+ end
112
+ end
113
+ end
165
114
 
166
115
  self.filter_attributes = []
167
116
 
168
117
  def self.connection_handler
169
- Thread.current.thread_variable_get(:ar_connection_handler) || default_connection_handler
118
+ ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] || default_connection_handler
170
119
  end
171
120
 
172
121
  def self.connection_handler=(handler)
173
- Thread.current.thread_variable_set(:ar_connection_handler, handler)
122
+ ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
174
123
  end
175
124
 
176
- def self.connection_handlers
177
- unless legacy_connection_handling
178
- raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
179
- end
180
-
181
- @@connection_handlers ||= {}
125
+ def self.asynchronous_queries_session # :nodoc:
126
+ asynchronous_queries_tracker.current_session
182
127
  end
183
128
 
184
- def self.connection_handlers=(handlers)
185
- unless legacy_connection_handling
186
- raise NotImplementedError, "The new connection handling does not setting support multiple connection handlers."
187
- end
188
-
189
- @@connection_handlers = handlers
129
+ def self.asynchronous_queries_tracker # :nodoc:
130
+ ActiveSupport::IsolatedExecutionState[:active_record_asynchronous_queries_tracker] ||= \
131
+ AsynchronousQueriesTracker.new
190
132
  end
191
133
 
192
134
  # Returns the symbol representing the current connected role.
@@ -199,16 +141,12 @@ module ActiveRecord
199
141
  # ActiveRecord::Base.current_role #=> :reading
200
142
  # end
201
143
  def self.current_role
202
- if ActiveRecord::Base.legacy_connection_handling
203
- connection_handlers.key(connection_handler) || default_role
204
- else
205
- connected_to_stack.reverse_each do |hash|
206
- return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
207
- return hash[:role] if hash[:role] && hash[:klasses].include?(connection_classes)
208
- end
209
-
210
- default_role
144
+ connected_to_stack.reverse_each do |hash|
145
+ return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
146
+ return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
211
147
  end
148
+
149
+ default_role
212
150
  end
213
151
 
214
152
  # Returns the symbol representing the current connected shard.
@@ -223,7 +161,7 @@ module ActiveRecord
223
161
  def self.current_shard
224
162
  connected_to_stack.reverse_each do |hash|
225
163
  return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
226
- return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_classes)
164
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_class_for_self)
227
165
  end
228
166
 
229
167
  default_shard
@@ -240,24 +178,20 @@ module ActiveRecord
240
178
  # ActiveRecord::Base.current_preventing_writes #=> false
241
179
  # end
242
180
  def self.current_preventing_writes
243
- if legacy_connection_handling
244
- connection_handler.prevent_writes
245
- else
246
- connected_to_stack.reverse_each do |hash|
247
- return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
248
- return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_classes)
249
- end
250
-
251
- false
181
+ connected_to_stack.reverse_each do |hash|
182
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
183
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
252
184
  end
185
+
186
+ false
253
187
  end
254
188
 
255
189
  def self.connected_to_stack # :nodoc:
256
- if connected_to_stack = Thread.current.thread_variable_get(:ar_connected_to_stack)
190
+ if connected_to_stack = ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack]
257
191
  connected_to_stack
258
192
  else
259
193
  connected_to_stack = Concurrent::Array.new
260
- Thread.current.thread_variable_set(:ar_connected_to_stack, connected_to_stack)
194
+ ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack] = connected_to_stack
261
195
  connected_to_stack
262
196
  end
263
197
  end
@@ -266,7 +200,7 @@ module ActiveRecord
266
200
  @connection_class = b
267
201
  end
268
202
 
269
- def self.connection_class # :nodoc
203
+ def self.connection_class # :nodoc:
270
204
  @connection_class ||= false
271
205
  end
272
206
 
@@ -274,7 +208,7 @@ module ActiveRecord
274
208
  self.connection_class
275
209
  end
276
210
 
277
- def self.connection_classes # :nodoc:
211
+ def self.connection_class_for_self # :nodoc:
278
212
  klass = self
279
213
 
280
214
  until klass == Base
@@ -285,22 +219,14 @@ module ActiveRecord
285
219
  klass
286
220
  end
287
221
 
288
- def self.allow_unsafe_raw_sql # :nodoc:
289
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql is deprecated and will be removed in Rails 7.0")
290
- end
291
-
292
- def self.allow_unsafe_raw_sql=(value) # :nodoc:
293
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql= is deprecated and will be removed in Rails 7.0")
294
- end
295
-
296
222
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
297
- self.default_role = writing_role
223
+ self.default_role = ActiveRecord.writing_role
298
224
  self.default_shard = :default
299
225
 
300
226
  def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
301
- case action_on_strict_loading_violation
227
+ case ActiveRecord.action_on_strict_loading_violation
302
228
  when :raise
303
- message = "`#{owner}` is marked for strict_loading. The `#{reflection.klass}` association named `:#{reflection.name}` cannot be lazily loaded."
229
+ message = reflection.strict_loading_violation_message(owner)
304
230
  raise ActiveRecord::StrictLoadingViolationError.new(message)
305
231
  when :log
306
232
  name = "strict_loading_violation.active_record"
@@ -314,19 +240,6 @@ module ActiveRecord
314
240
  @find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
315
241
  end
316
242
 
317
- def inherited(child_class) # :nodoc:
318
- # initialize cache at class definition for thread safety
319
- child_class.initialize_find_by_cache
320
- unless child_class.base_class?
321
- klass = self
322
- until klass.base_class?
323
- klass.initialize_find_by_cache
324
- klass = klass.superclass
325
- end
326
- end
327
- super
328
- end
329
-
330
243
  def find(*ids) # :nodoc:
331
244
  # We don't have cache keys for this stuff yet
332
245
  return super unless ids.length == 1
@@ -336,14 +249,8 @@ module ActiveRecord
336
249
 
337
250
  return super if StatementCache.unsupported_value?(id)
338
251
 
339
- key = primary_key
340
-
341
- statement = cached_find_by_statement(key) { |params|
342
- where(key => params.bind).limit(1)
343
- }
344
-
345
- statement.execute([id], connection).first ||
346
- raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
252
+ cached_find_by([primary_key], [id]) ||
253
+ raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}", name, primary_key, id))
347
254
  end
348
255
 
349
256
  def find_by(*args) # :nodoc:
@@ -365,31 +272,36 @@ module ActiveRecord
365
272
  elsif reflection.belongs_to? && !reflection.polymorphic?
366
273
  key = reflection.join_foreign_key
367
274
  pkey = reflection.join_primary_key
368
- value = value.public_send(pkey) if value.respond_to?(pkey)
275
+
276
+ if pkey.is_a?(Array)
277
+ if pkey.all? { |attribute| value.respond_to?(attribute) }
278
+ value = pkey.map do |attribute|
279
+ if attribute == "id"
280
+ value.id_value
281
+ else
282
+ value.public_send(attribute)
283
+ end
284
+ end
285
+ composite_primary_key = true
286
+ end
287
+ else
288
+ value = value.public_send(pkey) if value.respond_to?(pkey)
289
+ end
369
290
  end
370
291
 
371
- if !columns_hash.key?(key) || StatementCache.unsupported_value?(value)
292
+ if !composite_primary_key &&
293
+ (!columns_hash.key?(key) || StatementCache.unsupported_value?(value))
372
294
  return super
373
295
  end
374
296
 
375
297
  h[key] = value
376
298
  end
377
299
 
378
- keys = hash.keys
379
- statement = cached_find_by_statement(keys) { |params|
380
- wheres = keys.index_with { params.bind }
381
- where(wheres).limit(1)
382
- }
383
-
384
- begin
385
- statement.execute(hash.values, connection).first
386
- rescue TypeError
387
- raise ActiveRecord::StatementInvalid
388
- end
300
+ cached_find_by(hash.keys, hash.values)
389
301
  end
390
302
 
391
303
  def find_by!(*args) # :nodoc:
392
- find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
304
+ find_by(*args) || where(*args).raise_record_not_found_exception!
393
305
  end
394
306
 
395
307
  def initialize_generated_modules # :nodoc:
@@ -408,10 +320,10 @@ module ActiveRecord
408
320
 
409
321
  # Returns columns which shouldn't be exposed while calling +#inspect+.
410
322
  def filter_attributes
411
- if defined?(@filter_attributes)
412
- @filter_attributes
413
- else
323
+ if @filter_attributes.nil?
414
324
  superclass.filter_attributes
325
+ else
326
+ @filter_attributes
415
327
  end
416
328
  end
417
329
 
@@ -422,19 +334,19 @@ module ActiveRecord
422
334
  end
423
335
 
424
336
  def inspection_filter # :nodoc:
425
- if defined?(@filter_attributes)
337
+ if @filter_attributes.nil?
338
+ superclass.inspection_filter
339
+ else
426
340
  @inspection_filter ||= begin
427
341
  mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
428
342
  ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
429
343
  end
430
- else
431
- superclass.inspection_filter
432
344
  end
433
345
  end
434
346
 
435
347
  # Returns a string like 'Post(id:integer, title:string, body:text)'
436
348
  def inspect # :nodoc:
437
- if self == Base
349
+ if self == Base || singleton_class?
438
350
  super
439
351
  elsif abstract_class?
440
352
  "#{super}(abstract)"
@@ -448,25 +360,11 @@ module ActiveRecord
448
360
  end
449
361
  end
450
362
 
451
- # Overwrite the default class equality method to provide support for decorated models.
452
- def ===(object) # :nodoc:
453
- object.is_a?(self)
454
- end
455
-
456
- # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
457
- #
458
- # class Post < ActiveRecord::Base
459
- # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
460
- # end
363
+ # Returns an instance of +Arel::Table+ loaded with the current table name.
461
364
  def arel_table # :nodoc:
462
365
  @arel_table ||= Arel::Table.new(table_name, klass: self)
463
366
  end
464
367
 
465
- def arel_attribute(name, table = arel_table) # :nodoc:
466
- table[name]
467
- end
468
- deprecate :arel_attribute
469
-
470
368
  def predicate_builder # :nodoc:
471
369
  @predicate_builder ||= PredicateBuilder.new(table_metadata)
472
370
  end
@@ -475,16 +373,34 @@ module ActiveRecord
475
373
  TypeCaster::Map.new(self)
476
374
  end
477
375
 
478
- def _internal? # :nodoc:
479
- false
480
- end
481
-
482
376
  def cached_find_by_statement(key, &block) # :nodoc:
483
377
  cache = @find_by_statement_cache[connection.prepared_statements]
484
378
  cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
485
379
  end
486
380
 
487
381
  private
382
+ def inherited(subclass)
383
+ super
384
+
385
+ # initialize cache at class definition for thread safety
386
+ subclass.initialize_find_by_cache
387
+ unless subclass.base_class?
388
+ klass = self
389
+ until klass.base_class?
390
+ klass.initialize_find_by_cache
391
+ klass = klass.superclass
392
+ end
393
+ end
394
+
395
+ subclass.class_eval do
396
+ @arel_table = nil
397
+ @predicate_builder = nil
398
+ @inspection_filter = nil
399
+ @filter_attributes ||= nil
400
+ @generated_association_methods ||= nil
401
+ end
402
+ end
403
+
488
404
  def relation
489
405
  relation = Relation.create(self)
490
406
 
@@ -498,6 +414,25 @@ module ActiveRecord
498
414
  def table_metadata
499
415
  TableMetadata.new(self, arel_table)
500
416
  end
417
+
418
+ def cached_find_by(keys, values)
419
+ statement = cached_find_by_statement(keys) { |params|
420
+ wheres = keys.index_with do |key|
421
+ if key.is_a?(Array)
422
+ [key.map { params.bind }]
423
+ else
424
+ params.bind
425
+ end
426
+ end
427
+ where(wheres).limit(1)
428
+ }
429
+
430
+ begin
431
+ statement.execute(values.flatten, connection).first
432
+ rescue TypeError
433
+ raise ActiveRecord::StatementInvalid
434
+ end
435
+ end
501
436
  end
502
437
 
503
438
  # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -505,7 +440,7 @@ module ActiveRecord
505
440
  # In both instances, valid attribute keys are determined by the column names of the associated table --
506
441
  # hence you can't have attributes that aren't part of the table columns.
507
442
  #
508
- # ==== Example:
443
+ # ==== Example
509
444
  # # Instantiates a single new object
510
445
  # User.new(first_name: 'Jamie')
511
446
  def initialize(attributes = nil)
@@ -536,7 +471,7 @@ module ActiveRecord
536
471
  # post.init_with(coder)
537
472
  # post.title # => 'hello world'
538
473
  def init_with(coder, &block)
539
- coder = LegacyYamlAdapter.convert(self.class, coder)
474
+ coder = LegacyYamlAdapter.convert(coder)
540
475
  attributes = self.class.yaml_encoder.decode(coder)
541
476
  init_with_attributes(attributes, coder["new_record"], &block)
542
477
  end
@@ -583,12 +518,17 @@ module ActiveRecord
583
518
  # only, not its associations. The extent of a "deep" copy is application
584
519
  # specific and is therefore left to the application to implement according
585
520
  # to its need.
586
- # The dup method does not preserve the timestamps (created|updated)_(at|on).
521
+ # The dup method does not preserve the timestamps (created|updated)_(at|on)
522
+ # and locking column.
587
523
 
588
524
  ##
589
525
  def initialize_dup(other) # :nodoc:
590
526
  @attributes = @attributes.deep_dup
591
- @attributes.reset(@primary_key)
527
+ if self.class.composite_primary_key?
528
+ @primary_key.each { |key| @attributes.reset(key) }
529
+ else
530
+ @attributes.reset(@primary_key)
531
+ end
592
532
 
593
533
  _run_initialize_callbacks
594
534
 
@@ -618,6 +558,35 @@ module ActiveRecord
618
558
  coder["active_record_yaml_version"] = 2
619
559
  end
620
560
 
561
+ ##
562
+ # :method: slice
563
+ #
564
+ # :call-seq: slice(*methods)
565
+ #
566
+ # Returns a hash of the given methods with their names as keys and returned
567
+ # values as values.
568
+ #
569
+ # topic = Topic.new(title: "Budget", author_name: "Jason")
570
+ # topic.slice(:title, :author_name)
571
+ # => { "title" => "Budget", "author_name" => "Jason" }
572
+ #
573
+ #--
574
+ # Implemented by ActiveModel::Access#slice.
575
+
576
+ ##
577
+ # :method: values_at
578
+ #
579
+ # :call-seq: values_at(*methods)
580
+ #
581
+ # Returns an array of the values returned by the given methods.
582
+ #
583
+ # topic = Topic.new(title: "Budget", author_name: "Jason")
584
+ # topic.values_at(:title, :author_name)
585
+ # => ["Budget", "Jason"]
586
+ #
587
+ #--
588
+ # Implemented by ActiveModel::Access#values_at.
589
+
621
590
  # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
622
591
  # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
623
592
  #
@@ -630,7 +599,7 @@ module ActiveRecord
630
599
  def ==(comparison_object)
631
600
  super ||
632
601
  comparison_object.instance_of?(self.class) &&
633
- !id.nil? &&
602
+ primary_key_values_present? &&
634
603
  comparison_object.id == id
635
604
  end
636
605
  alias :eql? :==
@@ -638,7 +607,9 @@ module ActiveRecord
638
607
  # Delegates to id in order to allow two records of the same type and id to work with something like:
639
608
  # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
640
609
  def hash
641
- if id
610
+ id = self.id
611
+
612
+ if primary_key_values_present?
642
613
  self.class.hash ^ id.hash
643
614
  else
644
615
  super
@@ -689,14 +660,57 @@ module ActiveRecord
689
660
  # if the record tries to lazily load an association.
690
661
  #
691
662
  # user = User.first
692
- # user.strict_loading!
663
+ # user.strict_loading! # => true
664
+ # user.address.city
665
+ # => ActiveRecord::StrictLoadingViolationError
693
666
  # user.comments.to_a
694
667
  # => ActiveRecord::StrictLoadingViolationError
695
- def strict_loading!
696
- @strict_loading = true
668
+ #
669
+ # ==== Parameters
670
+ #
671
+ # * +value+ - Boolean specifying whether to enable or disable strict loading.
672
+ # * <tt>:mode</tt> - Symbol specifying strict loading mode. Defaults to :all. Using
673
+ # :n_plus_one_only mode will only raise an error if an association that
674
+ # will lead to an n plus one query is lazily loaded.
675
+ #
676
+ # ==== Examples
677
+ #
678
+ # user = User.first
679
+ # user.strict_loading!(false) # => false
680
+ # user.address.city # => "Tatooine"
681
+ # user.comments.to_a # => [#<Comment:0x00...]
682
+ #
683
+ # user.strict_loading!(mode: :n_plus_one_only)
684
+ # user.address.city # => "Tatooine"
685
+ # user.comments.to_a # => [#<Comment:0x00...]
686
+ # user.comments.first.ratings.to_a
687
+ # => ActiveRecord::StrictLoadingViolationError
688
+ def strict_loading!(value = true, mode: :all)
689
+ unless [:all, :n_plus_one_only].include?(mode)
690
+ raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
691
+ end
692
+
693
+ @strict_loading_mode = mode
694
+ @strict_loading = value
695
+ end
696
+
697
+ attr_reader :strict_loading_mode
698
+
699
+ # Returns +true+ if the record uses strict_loading with +:n_plus_one_only+ mode enabled.
700
+ def strict_loading_n_plus_one_only?
701
+ @strict_loading_mode == :n_plus_one_only
702
+ end
703
+
704
+ # Returns +true+ if the record uses strict_loading with +:all+ mode enabled.
705
+ def strict_loading_all?
706
+ @strict_loading_mode == :all
697
707
  end
698
708
 
699
709
  # Marks this record as read only.
710
+ #
711
+ # customer = Customer.first
712
+ # customer.readonly!
713
+ # customer.save # Raises an ActiveRecord::ReadOnlyRecord
700
714
  def readonly!
701
715
  @readonly = true
702
716
  end
@@ -710,11 +724,11 @@ module ActiveRecord
710
724
  # We check defined?(@attributes) not to issue warnings if the object is
711
725
  # allocated but not initialized.
712
726
  inspection = if defined?(@attributes) && @attributes
713
- self.class.attribute_names.collect do |name|
727
+ attribute_names.filter_map do |name|
714
728
  if _has_attribute?(name)
715
729
  "#{name}: #{attribute_for_inspect(name)}"
716
730
  end
717
- end.compact.join(", ")
731
+ end.join(", ")
718
732
  else
719
733
  "not initialized"
720
734
  end
@@ -747,16 +761,6 @@ module ActiveRecord
747
761
  end
748
762
  end
749
763
 
750
- # Returns a hash of the given methods with their names as keys and returned values as values.
751
- def slice(*methods)
752
- methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
753
- end
754
-
755
- # Returns an array of the values returned by the given methods.
756
- def values_at(*methods)
757
- methods.flatten.map! { |method| public_send(method) }
758
- end
759
-
760
764
  private
761
765
  # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
762
766
  # the array, and then rescues from the possible +NoMethodError+. If those elements are
@@ -771,16 +775,21 @@ module ActiveRecord
771
775
  end
772
776
 
773
777
  def init_internals
774
- @primary_key = self.class.primary_key
775
778
  @readonly = false
776
779
  @previously_new_record = false
777
780
  @destroyed = false
778
781
  @marked_for_destruction = false
779
782
  @destroyed_by_association = nil
780
783
  @_start_transaction_state = nil
781
- @strict_loading = self.class.strict_loading_by_default
782
784
 
783
- self.class.define_attribute_methods
785
+ klass = self.class
786
+
787
+ @primary_key = klass.primary_key
788
+ @strict_loading = klass.strict_loading_by_default
789
+ @strict_loading_mode = :all
790
+
791
+ klass.define_attribute_methods
792
+ klass.generate_alias_attributes
784
793
  end
785
794
 
786
795
  def initialize_internals_callback