activerecord 6.1.7 → 7.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +616 -1290
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +31 -31
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +17 -14
  7. data/lib/active_record/association_relation.rb +2 -12
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +60 -21
  10. data/lib/active_record/associations/association_scope.rb +17 -12
  11. data/lib/active_record/associations/belongs_to_association.rb +37 -11
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
  13. data/lib/active_record/associations/builder/association.rb +11 -5
  14. data/lib/active_record/associations/builder/belongs_to.rb +41 -14
  15. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +4 -4
  19. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  20. data/lib/active_record/associations/collection_association.rb +46 -36
  21. data/lib/active_record/associations/collection_proxy.rb +44 -16
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +10 -3
  25. data/lib/active_record/associations/has_many_association.rb +29 -19
  26. data/lib/active_record/associations/has_many_through_association.rb +19 -8
  27. data/lib/active_record/associations/has_one_association.rb +20 -10
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
  30. data/lib/active_record/associations/join_dependency.rb +28 -20
  31. data/lib/active_record/associations/nested_error.rb +47 -0
  32. data/lib/active_record/associations/preloader/association.rb +212 -53
  33. data/lib/active_record/associations/preloader/batch.rb +48 -0
  34. data/lib/active_record/associations/preloader/branch.rb +153 -0
  35. data/lib/active_record/associations/preloader/through_association.rb +50 -16
  36. data/lib/active_record/associations/preloader.rb +50 -121
  37. data/lib/active_record/associations/singular_association.rb +15 -3
  38. data/lib/active_record/associations/through_association.rb +25 -14
  39. data/lib/active_record/associations.rb +429 -522
  40. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  41. data/lib/active_record/attribute_assignment.rb +1 -5
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  43. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  44. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  45. data/lib/active_record/attribute_methods/primary_key.rb +47 -27
  46. data/lib/active_record/attribute_methods/query.rb +31 -19
  47. data/lib/active_record/attribute_methods/read.rb +14 -11
  48. data/lib/active_record/attribute_methods/serialization.rb +174 -37
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +15 -9
  50. data/lib/active_record/attribute_methods/write.rb +12 -15
  51. data/lib/active_record/attribute_methods.rb +164 -52
  52. data/lib/active_record/attributes.rb +57 -54
  53. data/lib/active_record/autosave_association.rb +74 -57
  54. data/lib/active_record/base.rb +27 -5
  55. data/lib/active_record/callbacks.rb +19 -35
  56. data/lib/active_record/coders/column_serializer.rb +61 -0
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +70 -46
  59. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +325 -604
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +230 -64
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -143
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +348 -165
  75. data/lib/active_record/connection_adapters/column.rb +13 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
  78. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
  79. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  81. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  82. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
  83. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
  85. data/lib/active_record/connection_adapters/pool_config.rb +26 -16
  86. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  87. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  88. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
  89. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  94. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  100. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
  103. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  104. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  105. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
  106. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  107. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +403 -77
  108. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  109. data/lib/active_record/connection_adapters/postgresql_adapter.rb +520 -253
  110. data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
  111. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  112. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
  113. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
  114. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  116. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
  119. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  120. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  121. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  122. data/lib/active_record/connection_adapters.rb +130 -6
  123. data/lib/active_record/connection_handling.rb +132 -146
  124. data/lib/active_record/core.rb +310 -253
  125. data/lib/active_record/counter_cache.rb +68 -34
  126. data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -4
  127. data/lib/active_record/database_configurations/database_config.rb +34 -10
  128. data/lib/active_record/database_configurations/hash_config.rb +107 -31
  129. data/lib/active_record/database_configurations/url_config.rb +38 -13
  130. data/lib/active_record/database_configurations.rb +96 -60
  131. data/lib/active_record/delegated_type.rb +90 -20
  132. data/lib/active_record/deprecator.rb +7 -0
  133. data/lib/active_record/destroy_association_async_job.rb +4 -2
  134. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  135. data/lib/active_record/dynamic_matchers.rb +3 -3
  136. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +68 -0
  140. data/lib/active_record/encryption/configurable.rb +60 -0
  141. data/lib/active_record/encryption/context.rb +42 -0
  142. data/lib/active_record/encryption/contexts.rb +76 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +170 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +53 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  159. data/lib/active_record/encryption/message_serializer.rb +96 -0
  160. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  161. data/lib/active_record/encryption/properties.rb +76 -0
  162. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  163. data/lib/active_record/encryption/scheme.rb +100 -0
  164. data/lib/active_record/encryption.rb +58 -0
  165. data/lib/active_record/enum.rb +170 -62
  166. data/lib/active_record/errors.rb +210 -27
  167. data/lib/active_record/explain.rb +21 -12
  168. data/lib/active_record/explain_registry.rb +11 -6
  169. data/lib/active_record/explain_subscriber.rb +1 -1
  170. data/lib/active_record/fixture_set/file.rb +15 -1
  171. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  172. data/lib/active_record/fixture_set/render_context.rb +2 -0
  173. data/lib/active_record/fixture_set/table_row.rb +70 -14
  174. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  175. data/lib/active_record/fixtures.rb +179 -112
  176. data/lib/active_record/future_result.rb +178 -0
  177. data/lib/active_record/gem_version.rb +4 -4
  178. data/lib/active_record/inheritance.rb +85 -31
  179. data/lib/active_record/insert_all.rb +148 -32
  180. data/lib/active_record/integration.rb +14 -10
  181. data/lib/active_record/internal_metadata.rb +123 -23
  182. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  183. data/lib/active_record/locking/optimistic.rb +43 -27
  184. data/lib/active_record/locking/pessimistic.rb +15 -6
  185. data/lib/active_record/log_subscriber.rb +41 -29
  186. data/lib/active_record/marshalling.rb +59 -0
  187. data/lib/active_record/message_pack.rb +124 -0
  188. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  189. data/lib/active_record/middleware/database_selector.rb +23 -13
  190. data/lib/active_record/middleware/shard_selector.rb +62 -0
  191. data/lib/active_record/migration/command_recorder.rb +113 -16
  192. data/lib/active_record/migration/compatibility.rb +235 -46
  193. data/lib/active_record/migration/default_strategy.rb +22 -0
  194. data/lib/active_record/migration/execution_strategy.rb +19 -0
  195. data/lib/active_record/migration/join_table.rb +1 -1
  196. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  197. data/lib/active_record/migration.rb +374 -177
  198. data/lib/active_record/model_schema.rb +145 -158
  199. data/lib/active_record/nested_attributes.rb +61 -23
  200. data/lib/active_record/no_touching.rb +3 -3
  201. data/lib/active_record/normalization.rb +163 -0
  202. data/lib/active_record/persistence.rb +282 -283
  203. data/lib/active_record/promise.rb +84 -0
  204. data/lib/active_record/query_cache.rb +18 -25
  205. data/lib/active_record/query_logs.rb +189 -0
  206. data/lib/active_record/query_logs_formatter.rb +41 -0
  207. data/lib/active_record/querying.rb +44 -9
  208. data/lib/active_record/railtie.rb +229 -71
  209. data/lib/active_record/railties/controller_runtime.rb +25 -11
  210. data/lib/active_record/railties/databases.rake +189 -256
  211. data/lib/active_record/railties/job_runtime.rb +23 -0
  212. data/lib/active_record/readonly_attributes.rb +41 -3
  213. data/lib/active_record/reflection.rb +332 -103
  214. data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
  215. data/lib/active_record/relation/batches.rb +200 -65
  216. data/lib/active_record/relation/calculations.rb +301 -112
  217. data/lib/active_record/relation/delegation.rb +33 -22
  218. data/lib/active_record/relation/finder_methods.rb +123 -52
  219. data/lib/active_record/relation/merger.rb +26 -19
  220. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  221. data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
  222. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  223. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  224. data/lib/active_record/relation/predicate_builder.rb +29 -22
  225. data/lib/active_record/relation/query_attribute.rb +30 -12
  226. data/lib/active_record/relation/query_methods.rb +870 -163
  227. data/lib/active_record/relation/record_fetch_warning.rb +10 -9
  228. data/lib/active_record/relation/spawn_methods.rb +7 -6
  229. data/lib/active_record/relation/where_clause.rb +15 -36
  230. data/lib/active_record/relation.rb +736 -145
  231. data/lib/active_record/result.rb +67 -54
  232. data/lib/active_record/runtime_registry.rb +71 -13
  233. data/lib/active_record/sanitization.rb +84 -34
  234. data/lib/active_record/schema.rb +39 -23
  235. data/lib/active_record/schema_dumper.rb +90 -31
  236. data/lib/active_record/schema_migration.rb +74 -23
  237. data/lib/active_record/scoping/default.rb +72 -15
  238. data/lib/active_record/scoping/named.rb +6 -13
  239. data/lib/active_record/scoping.rb +65 -34
  240. data/lib/active_record/secure_password.rb +60 -0
  241. data/lib/active_record/secure_token.rb +21 -3
  242. data/lib/active_record/serialization.rb +6 -1
  243. data/lib/active_record/signed_id.rb +30 -9
  244. data/lib/active_record/statement_cache.rb +7 -7
  245. data/lib/active_record/store.rb +10 -10
  246. data/lib/active_record/suppressor.rb +13 -15
  247. data/lib/active_record/table_metadata.rb +7 -3
  248. data/lib/active_record/tasks/database_tasks.rb +288 -149
  249. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  250. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  251. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  252. data/lib/active_record/test_databases.rb +1 -1
  253. data/lib/active_record/test_fixtures.rb +173 -155
  254. data/lib/active_record/testing/query_assertions.rb +121 -0
  255. data/lib/active_record/timestamp.rb +32 -19
  256. data/lib/active_record/token_for.rb +123 -0
  257. data/lib/active_record/touch_later.rb +12 -7
  258. data/lib/active_record/transaction.rb +132 -0
  259. data/lib/active_record/transactions.rb +118 -41
  260. data/lib/active_record/translation.rb +3 -5
  261. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  262. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  263. data/lib/active_record/type/internal/timezone.rb +7 -2
  264. data/lib/active_record/type/serialized.rb +9 -7
  265. data/lib/active_record/type/time.rb +4 -0
  266. data/lib/active_record/type/type_map.rb +17 -20
  267. data/lib/active_record/type.rb +1 -2
  268. data/lib/active_record/type_caster/connection.rb +4 -4
  269. data/lib/active_record/validations/absence.rb +1 -1
  270. data/lib/active_record/validations/associated.rb +13 -7
  271. data/lib/active_record/validations/numericality.rb +5 -4
  272. data/lib/active_record/validations/presence.rb +5 -28
  273. data/lib/active_record/validations/uniqueness.rb +65 -15
  274. data/lib/active_record/validations.rb +12 -5
  275. data/lib/active_record/version.rb +1 -1
  276. data/lib/active_record.rb +444 -32
  277. data/lib/arel/alias_predication.rb +1 -1
  278. data/lib/arel/attributes/attribute.rb +0 -8
  279. data/lib/arel/collectors/bind.rb +2 -0
  280. data/lib/arel/collectors/composite.rb +7 -0
  281. data/lib/arel/collectors/sql_string.rb +1 -1
  282. data/lib/arel/collectors/substitute_binds.rb +1 -1
  283. data/lib/arel/crud.rb +28 -22
  284. data/lib/arel/delete_manager.rb +18 -4
  285. data/lib/arel/errors.rb +10 -0
  286. data/lib/arel/factory_methods.rb +4 -0
  287. data/lib/arel/filter_predications.rb +9 -0
  288. data/lib/arel/insert_manager.rb +2 -3
  289. data/lib/arel/nodes/binary.rb +6 -7
  290. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  291. data/lib/arel/nodes/casted.rb +1 -1
  292. data/lib/arel/nodes/cte.rb +36 -0
  293. data/lib/arel/nodes/delete_statement.rb +12 -13
  294. data/lib/arel/nodes/filter.rb +10 -0
  295. data/lib/arel/nodes/fragments.rb +35 -0
  296. data/lib/arel/nodes/function.rb +1 -0
  297. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  298. data/lib/arel/nodes/insert_statement.rb +2 -2
  299. data/lib/arel/nodes/leading_join.rb +8 -0
  300. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  301. data/lib/arel/nodes/node.rb +115 -5
  302. data/lib/arel/nodes/select_core.rb +2 -2
  303. data/lib/arel/nodes/select_statement.rb +2 -2
  304. data/lib/arel/nodes/sql_literal.rb +13 -0
  305. data/lib/arel/nodes/table_alias.rb +4 -0
  306. data/lib/arel/nodes/update_statement.rb +8 -3
  307. data/lib/arel/nodes.rb +7 -2
  308. data/lib/arel/predications.rb +14 -4
  309. data/lib/arel/select_manager.rb +11 -5
  310. data/lib/arel/table.rb +9 -6
  311. data/lib/arel/tree_manager.rb +8 -15
  312. data/lib/arel/update_manager.rb +20 -5
  313. data/lib/arel/visitors/dot.rb +81 -90
  314. data/lib/arel/visitors/mysql.rb +23 -5
  315. data/lib/arel/visitors/postgresql.rb +1 -22
  316. data/lib/arel/visitors/sqlite.rb +25 -0
  317. data/lib/arel/visitors/to_sql.rb +170 -36
  318. data/lib/arel/visitors/visitor.rb +2 -2
  319. data/lib/arel.rb +23 -4
  320. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  321. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  322. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  323. data/lib/rails/generators/active_record/migration.rb +3 -1
  324. data/lib/rails/generators/active_record/model/USAGE +113 -0
  325. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  326. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  327. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  328. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  329. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  330. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  331. metadata +103 -17
  332. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  333. data/lib/active_record/null_relation.rb +0 -67
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/json"
4
+
5
+ module ActiveRecord
6
+ module TokenFor
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :token_definitions, instance_accessor: false, instance_predicate: false, default: {}
11
+ class_attribute :generated_token_verifier, instance_accessor: false, instance_predicate: false
12
+ end
13
+
14
+ TokenDefinition = Struct.new(:defining_class, :purpose, :expires_in, :block) do # :nodoc:
15
+ def full_purpose
16
+ @full_purpose ||= [defining_class.name, purpose, expires_in].join("\n")
17
+ end
18
+
19
+ def message_verifier
20
+ defining_class.generated_token_verifier
21
+ end
22
+
23
+ def payload_for(model)
24
+ block ? [model.id, model.instance_eval(&block).as_json] : [model.id]
25
+ end
26
+
27
+ def generate_token(model)
28
+ message_verifier.generate(payload_for(model), expires_in: expires_in, purpose: full_purpose)
29
+ end
30
+
31
+ def resolve_token(token)
32
+ payload = message_verifier.verified(token, purpose: full_purpose)
33
+ model = yield(payload[0]) if payload
34
+ model if model && payload_for(model) == payload
35
+ end
36
+ end
37
+
38
+ module RelationMethods
39
+ # Finds a record using a given +token+ for a predefined +purpose+. Returns
40
+ # +nil+ if the token is invalid or the record was not found.
41
+ def find_by_token_for(purpose, token)
42
+ raise UnknownPrimaryKey.new(self) unless model.primary_key
43
+ model.token_definitions.fetch(purpose).resolve_token(token) { |id| find_by(model.primary_key => id) }
44
+ end
45
+
46
+ # Finds a record using a given +token+ for a predefined +purpose+. Raises
47
+ # ActiveSupport::MessageVerifier::InvalidSignature if the token is invalid
48
+ # (e.g. expired, bad format, etc). Raises ActiveRecord::RecordNotFound if
49
+ # the token is valid but the record was not found.
50
+ def find_by_token_for!(purpose, token)
51
+ model.token_definitions.fetch(purpose).resolve_token(token) { |id| find(id) } ||
52
+ (raise ActiveSupport::MessageVerifier::InvalidSignature)
53
+ end
54
+ end
55
+
56
+ module ClassMethods
57
+ # Defines the behavior of tokens generated for a specific +purpose+.
58
+ # A token can be generated by calling TokenFor#generate_token_for on a
59
+ # record. Later, that record can be fetched by calling #find_by_token_for
60
+ # (or #find_by_token_for!) with the same purpose and token.
61
+ #
62
+ # Tokens are signed so that they are tamper-proof. Thus they can be
63
+ # exposed to outside world as, for example, password reset tokens.
64
+ #
65
+ # By default, tokens do not expire. They can be configured to expire by
66
+ # specifying a duration via the +expires_in+ option. The duration becomes
67
+ # part of the token's signature, so changing the value of +expires_in+
68
+ # will automatically invalidate previously generated tokens.
69
+ #
70
+ # A block may also be specified. When generating a token with
71
+ # TokenFor#generate_token_for, the block will be evaluated in the context
72
+ # of the record, and its return value will be embedded in the token as
73
+ # JSON. Later, when fetching the record with #find_by_token_for, the block
74
+ # will be evaluated again in the context of the fetched record. If the two
75
+ # JSON values do not match, the token will be treated as invalid. Note
76
+ # that the value returned by the block <b>should not contain sensitive
77
+ # information</b> because it will be embedded in the token as
78
+ # <b>human-readable plaintext JSON</b>.
79
+ #
80
+ # ==== Examples
81
+ #
82
+ # class User < ActiveRecord::Base
83
+ # has_secure_password
84
+ #
85
+ # generates_token_for :password_reset, expires_in: 15.minutes do
86
+ # # Last 10 characters of password salt, which changes when password is updated:
87
+ # password_salt&.last(10)
88
+ # end
89
+ # end
90
+ #
91
+ # user = User.first
92
+ #
93
+ # token = user.generate_token_for(:password_reset)
94
+ # User.find_by_token_for(:password_reset, token) # => user
95
+ # # 16 minutes later...
96
+ # User.find_by_token_for(:password_reset, token) # => nil
97
+ #
98
+ # token = user.generate_token_for(:password_reset)
99
+ # User.find_by_token_for(:password_reset, token) # => user
100
+ # user.update!(password: "new password")
101
+ # User.find_by_token_for(:password_reset, token) # => nil
102
+ def generates_token_for(purpose, expires_in: nil, &block)
103
+ self.token_definitions = token_definitions.merge(purpose => TokenDefinition.new(self, purpose, expires_in, block))
104
+ end
105
+
106
+ def find_by_token_for(purpose, token) # :nodoc:
107
+ all.find_by_token_for(purpose, token)
108
+ end
109
+
110
+ def find_by_token_for!(purpose, token) # :nodoc:
111
+ all.find_by_token_for!(purpose, token)
112
+ end
113
+ end
114
+
115
+ # Generates a token for a predefined +purpose+.
116
+ #
117
+ # Use ClassMethods#generates_token_for to define a token purpose and
118
+ # behavior.
119
+ def generate_token_for(purpose)
120
+ self.class.token_definitions.fetch(purpose).generate_token(self)
121
+ end
122
+ end
123
+ end
@@ -24,9 +24,13 @@ module ActiveRecord
24
24
  @_new_record_before_last_commit ||= false
25
25
 
26
26
  # touch the parents as we are not calling the after_save callbacks
27
- self.class.reflect_on_all_associations(:belongs_to).each do |r|
27
+ self.class.reflect_on_all_associations.each do |r|
28
28
  if touch = r.options[:touch]
29
- ActiveRecord::Associations::Builder::BelongsTo.touch_record(self, changes_to_save, r.foreign_key, r.name, touch, :touch_later)
29
+ if r.macro == :belongs_to
30
+ ActiveRecord::Associations::Builder::BelongsTo.touch_record(self, changes_to_save, r.foreign_key, r.name, touch)
31
+ elsif r.macro == :has_one
32
+ ActiveRecord::Associations::Builder::HasOne.touch_record(self, r.name, touch)
33
+ end
30
34
  end
31
35
  end
32
36
  end
@@ -42,6 +46,11 @@ module ActiveRecord
42
46
  end
43
47
 
44
48
  private
49
+ def init_internals
50
+ super
51
+ @_defer_touch_attrs = nil
52
+ end
53
+
45
54
  def surreptitiously_touch(attr_names)
46
55
  attr_names.each do |attr_name|
47
56
  _write_attribute(attr_name, @_touch_time)
@@ -55,11 +64,7 @@ module ActiveRecord
55
64
  end
56
65
 
57
66
  def has_defer_touch_attrs?
58
- defined?(@_defer_touch_attrs) && @_defer_touch_attrs.present?
59
- end
60
-
61
- def belongs_to_touch_method
62
- :touch_later
67
+ @_defer_touch_attrs.present?
63
68
  end
64
69
  end
65
70
  end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/digest"
4
+
5
+ module ActiveRecord
6
+ # Class specifies the interface to interact with the current transaction state.
7
+ #
8
+ # It can either map to an actual transaction/savepoint, or represent the
9
+ # absence of a transaction.
10
+ #
11
+ # == State
12
+ #
13
+ # We say that a transaction is _finalized_ when it wraps a real transaction
14
+ # that has been either committed or rolled back.
15
+ #
16
+ # A transaction is _open_ if it wraps a real transaction that is not finalized.
17
+ #
18
+ # On the other hand, a transaction is _closed_ when it is not open. That is,
19
+ # when it represents absence of transaction, or it wraps a real but finalized
20
+ # one.
21
+ #
22
+ # You can check whether a transaction is open or closed with the +open?+ and
23
+ # +closed?+ predicates:
24
+ #
25
+ # if Article.current_transaction.open?
26
+ # # We are inside a real and not finalized transaction.
27
+ # end
28
+ #
29
+ # Closed transactions are `blank?` too.
30
+ #
31
+ # == Callbacks
32
+ #
33
+ # After updating the database state, you may sometimes need to perform some extra work, or reflect these
34
+ # changes in a remote system like clearing or updating a cache:
35
+ #
36
+ # def publish_article(article)
37
+ # article.update!(published: true)
38
+ # NotificationService.article_published(article)
39
+ # end
40
+ #
41
+ # The above code works but has one important flaw, which is that it no longer works properly if called inside
42
+ # a transaction, as it will interact with the remote system before the changes are persisted:
43
+ #
44
+ # Article.transaction do
45
+ # article = create_article(article)
46
+ # publish_article(article)
47
+ # end
48
+ #
49
+ # The callbacks offered by ActiveRecord::Transaction allow to rewriting this method in a way that is compatible
50
+ # with transactions:
51
+ #
52
+ # def publish_article(article)
53
+ # article.update!(published: true)
54
+ # Article.current_transaction.after_commit do
55
+ # NotificationService.article_published(article)
56
+ # end
57
+ # end
58
+ #
59
+ # In the above example, if +publish_article+ is called inside a transaction, the callback will be invoked
60
+ # after the transaction is successfully committed, and if called outside a transaction, the callback will be invoked
61
+ # immediately.
62
+ #
63
+ # == Caveats
64
+ #
65
+ # When using after_commit callbacks, it is important to note that if the callback raises an error, the transaction
66
+ # won't be rolled back as it was already committed. Relying solely on these to synchronize state between multiple
67
+ # systems may lead to consistency issues.
68
+ class Transaction
69
+ def initialize(internal_transaction) # :nodoc:
70
+ @internal_transaction = internal_transaction
71
+ @uuid = nil
72
+ end
73
+
74
+ # Registers a block to be called after the transaction is fully committed.
75
+ #
76
+ # If there is no currently open transactions, the block is called
77
+ # immediately, unless the transaction is finalized, in which case attempting
78
+ # to register the callback raises ActiveRecord::ActiveRecordError.
79
+ #
80
+ # If the transaction has a parent transaction, the callback is transferred to
81
+ # the parent when the current transaction commits, or dropped when the current transaction
82
+ # is rolled back. This operation is repeated until the outermost transaction is reached.
83
+ #
84
+ # If the callback raises an error, the transaction remains committed.
85
+ def after_commit(&block)
86
+ if @internal_transaction.nil?
87
+ yield
88
+ else
89
+ @internal_transaction.after_commit(&block)
90
+ end
91
+ end
92
+
93
+ # Registers a block to be called after the transaction is rolled back.
94
+ #
95
+ # If there is no currently open transactions, the block is not called. But
96
+ # if the transaction is finalized, attempting to register the callback
97
+ # raises ActiveRecord::ActiveRecordError.
98
+ #
99
+ # If the transaction is successfully committed but has a parent
100
+ # transaction, the callback is automatically added to the parent transaction.
101
+ #
102
+ # If the entire chain of nested transactions are all successfully committed,
103
+ # the block is never called.
104
+ #
105
+ # If the transaction is already finalized, attempting to register a callback
106
+ # will raise ActiveRecord::ActiveRecordError.
107
+ def after_rollback(&block)
108
+ @internal_transaction&.after_rollback(&block)
109
+ end
110
+
111
+ # Returns true if the transaction exists and isn't finalized yet.
112
+ def open?
113
+ !closed?
114
+ end
115
+
116
+ # Returns true if the transaction doesn't exist or is finalized.
117
+ def closed?
118
+ @internal_transaction.nil? || @internal_transaction.state.finalized?
119
+ end
120
+
121
+ alias_method :blank?, :closed?
122
+
123
+ # Returns a UUID for this transaction or +nil+ if no transaction is open.
124
+ def uuid
125
+ if @internal_transaction
126
+ @uuid ||= Digest::UUID.uuid_v4
127
+ end
128
+ end
129
+
130
+ NULL_TRANSACTION = new(nil).freeze
131
+ end
132
+ end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  # See ActiveRecord::Transactions::ClassMethods for documentation.
5
5
  module Transactions
6
6
  extend ActiveSupport::Concern
7
- #:nodoc:
7
+ # :nodoc:
8
8
  ACTIONS = [:create, :destroy, :update]
9
9
 
10
10
  included do
@@ -13,7 +13,9 @@ module ActiveRecord
13
13
  scope: [:kind, :name]
14
14
  end
15
15
 
16
- # = Active Record Transactions
16
+ attr_accessor :_new_record_before_last_commit # :nodoc:
17
+
18
+ # = Active Record \Transactions
17
19
  #
18
20
  # \Transactions are protective blocks where SQL statements are only permanent
19
21
  # if they can all succeed as one atomic action. The classic example is a
@@ -98,7 +100,8 @@ module ActiveRecord
98
100
  # catch those in your application code.
99
101
  #
100
102
  # One exception is the ActiveRecord::Rollback exception, which will trigger
101
- # a ROLLBACK when raised, but not be re-raised by the transaction block.
103
+ # a ROLLBACK when raised, but not be re-raised by the transaction block. Any
104
+ # other exception will be re-raised.
102
105
  #
103
106
  # *Warning*: one should not catch ActiveRecord::StatementInvalid exceptions
104
107
  # inside a transaction block. ActiveRecord::StatementInvalid exceptions indicate that an
@@ -185,6 +188,27 @@ module ActiveRecord
185
188
  # #after_commit is a good spot to put in a hook to clearing a cache since clearing it from
186
189
  # within a transaction could trigger the cache to be regenerated before the database is updated.
187
190
  #
191
+ # ==== NOTE: Callbacks are deduplicated per callback by filter.
192
+ #
193
+ # Trying to define multiple callbacks with the same filter will result in a single callback being run.
194
+ #
195
+ # For example:
196
+ #
197
+ # after_commit :do_something
198
+ # after_commit :do_something # only the last one will be called
199
+ #
200
+ # This applies to all variations of <tt>after_*_commit</tt> callbacks as well.
201
+ #
202
+ # after_commit :do_something
203
+ # after_create_commit :do_something
204
+ # after_save_commit :do_something
205
+ #
206
+ # It is recommended to use the +on:+ option to specify when the callback should be run.
207
+ #
208
+ # after_commit :do_something, on: [:create, :update]
209
+ #
210
+ # This is equivalent to using +after_create_commit+ and +after_update_commit+, but will not be deduplicated.
211
+ #
188
212
  # === Caveats
189
213
  #
190
214
  # If you're on MySQL, then do not use Data Definition Language (DDL) operations in nested
@@ -195,9 +219,9 @@ module ActiveRecord
195
219
  # database error will occur because the savepoint has already been
196
220
  # automatically released. The following example demonstrates the problem:
197
221
  #
198
- # Model.connection.transaction do # BEGIN
199
- # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
200
- # Model.connection.create_table(...) # active_record_1 now automatically released
222
+ # Model.lease_connection.transaction do # BEGIN
223
+ # Model.lease_connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
224
+ # Model.lease_connection.create_table(...) # active_record_1 now automatically released
201
225
  # end # RELEASE SAVEPOINT active_record_1
202
226
  # # ^^^^ BOOM! database error!
203
227
  # end
@@ -206,7 +230,20 @@ module ActiveRecord
206
230
  module ClassMethods
207
231
  # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
208
232
  def transaction(**options, &block)
209
- connection.transaction(**options, &block)
233
+ with_connection do |connection|
234
+ connection.transaction(**options, &block)
235
+ end
236
+ end
237
+
238
+ # Returns a representation of the current transaction state,
239
+ # which can be a top level transaction, a savepoint, or the absence of a transaction.
240
+ #
241
+ # An object is always returned, whether or not a transaction is currently active.
242
+ # To check if a transaction was opened, use <tt>current_transaction.open?</tt>.
243
+ #
244
+ # See the ActiveRecord::Transaction documentation for detailed behavior.
245
+ def current_transaction
246
+ connection_pool.active_connection&.current_transaction&.user_transaction || Transaction::NULL_TRANSACTION
210
247
  end
211
248
 
212
249
  def before_commit(*args, &block) # :nodoc:
@@ -227,31 +264,31 @@ module ActiveRecord
227
264
  # after_commit :do_bar_baz, on: [:update, :destroy]
228
265
  #
229
266
  def after_commit(*args, &block)
230
- set_options_for_callbacks!(args)
267
+ set_options_for_callbacks!(args, prepend_option)
231
268
  set_callback(:commit, :after, *args, &block)
232
269
  end
233
270
 
234
271
  # Shortcut for <tt>after_commit :hook, on: [ :create, :update ]</tt>.
235
272
  def after_save_commit(*args, &block)
236
- set_options_for_callbacks!(args, on: [ :create, :update ])
273
+ set_options_for_callbacks!(args, on: [ :create, :update ], **prepend_option)
237
274
  set_callback(:commit, :after, *args, &block)
238
275
  end
239
276
 
240
277
  # Shortcut for <tt>after_commit :hook, on: :create</tt>.
241
278
  def after_create_commit(*args, &block)
242
- set_options_for_callbacks!(args, on: :create)
279
+ set_options_for_callbacks!(args, on: :create, **prepend_option)
243
280
  set_callback(:commit, :after, *args, &block)
244
281
  end
245
282
 
246
283
  # Shortcut for <tt>after_commit :hook, on: :update</tt>.
247
284
  def after_update_commit(*args, &block)
248
- set_options_for_callbacks!(args, on: :update)
285
+ set_options_for_callbacks!(args, on: :update, **prepend_option)
249
286
  set_callback(:commit, :after, *args, &block)
250
287
  end
251
288
 
252
289
  # Shortcut for <tt>after_commit :hook, on: :destroy</tt>.
253
290
  def after_destroy_commit(*args, &block)
254
- set_options_for_callbacks!(args, on: :destroy)
291
+ set_options_for_callbacks!(args, on: :destroy, **prepend_option)
255
292
  set_callback(:commit, :after, *args, &block)
256
293
  end
257
294
 
@@ -259,11 +296,38 @@ module ActiveRecord
259
296
  #
260
297
  # Please check the documentation of #after_commit for options.
261
298
  def after_rollback(*args, &block)
262
- set_options_for_callbacks!(args)
299
+ set_options_for_callbacks!(args, prepend_option)
263
300
  set_callback(:rollback, :after, *args, &block)
264
301
  end
265
302
 
303
+ # Similar to ActiveSupport::Callbacks::ClassMethods#set_callback, but with
304
+ # support for options available on #after_commit and #after_rollback callbacks.
305
+ def set_callback(name, *filter_list, &block)
306
+ options = filter_list.extract_options!
307
+ filter_list << options
308
+
309
+ if name.in?([:commit, :rollback]) && options[:on]
310
+ fire_on = Array(options[:on])
311
+ assert_valid_transaction_action(fire_on)
312
+ options[:if] = [
313
+ -> { transaction_include_any_action?(fire_on) },
314
+ *options[:if]
315
+ ]
316
+ end
317
+
318
+
319
+ super(name, *filter_list, &block)
320
+ end
321
+
266
322
  private
323
+ def prepend_option
324
+ if ActiveRecord.run_after_transaction_callbacks_in_order_defined
325
+ { prepend: true }
326
+ else
327
+ {}
328
+ end
329
+ end
330
+
267
331
  def set_options_for_callbacks!(args, enforced_options = {})
268
332
  options = args.extract_options!.merge!(enforced_options)
269
333
  args << options
@@ -290,19 +354,19 @@ module ActiveRecord
290
354
  self.class.transaction(**options, &block)
291
355
  end
292
356
 
293
- def destroy #:nodoc:
357
+ def destroy # :nodoc:
294
358
  with_transaction_returning_status { super }
295
359
  end
296
360
 
297
- def save(**) #:nodoc:
361
+ def save(**) # :nodoc:
298
362
  with_transaction_returning_status { super }
299
363
  end
300
364
 
301
- def save!(**) #:nodoc:
365
+ def save!(**) # :nodoc:
302
366
  with_transaction_returning_status { super }
303
367
  end
304
368
 
305
- def touch(*, **) #:nodoc:
369
+ def touch(*, **) # :nodoc:
306
370
  with_transaction_returning_status { super }
307
371
  end
308
372
 
@@ -314,8 +378,8 @@ module ActiveRecord
314
378
  #
315
379
  # Ensure that it is not called if the object was never persisted (failed create),
316
380
  # but call it after the commit of a destroyed object.
317
- def committed!(should_run_callbacks: true) #:nodoc:
318
- force_clear_transaction_record_state
381
+ def committed!(should_run_callbacks: true) # :nodoc:
382
+ @_start_transaction_state = nil
319
383
  if should_run_callbacks
320
384
  @_committed_already_called = true
321
385
  _run_commit_callbacks
@@ -326,7 +390,7 @@ module ActiveRecord
326
390
 
327
391
  # Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
328
392
  # state should be rolled back to the beginning or just to the last savepoint.
329
- def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
393
+ def rolledback!(force_restore_state: false, should_run_callbacks: true) # :nodoc:
330
394
  if should_run_callbacks
331
395
  _run_rollback_callbacks
332
396
  end
@@ -336,25 +400,26 @@ module ActiveRecord
336
400
  @_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state
337
401
  end
338
402
 
339
- # Executes +method+ within a transaction and captures its return value as a
340
- # status flag. If the status is true the transaction is committed, otherwise
341
- # a ROLLBACK is issued. In any case the status flag is returned.
403
+ # Executes a block within a transaction and captures its return value as a
404
+ # status flag. If the status is true, the transaction is committed,
405
+ # otherwise a ROLLBACK is issued. In any case, the status flag is returned.
342
406
  #
343
407
  # This method is available within the context of an ActiveRecord::Base
344
408
  # instance.
345
409
  def with_transaction_returning_status
346
- status = nil
347
- connection = self.class.connection
348
- ensure_finalize = !connection.transaction_open?
410
+ self.class.with_connection do |connection|
411
+ status = nil
412
+ ensure_finalize = !connection.transaction_open?
349
413
 
350
- connection.transaction do
351
- add_to_transaction(ensure_finalize || has_transactional_callbacks?)
352
- remember_transaction_record_state
414
+ connection.transaction do
415
+ add_to_transaction(ensure_finalize || has_transactional_callbacks?)
416
+ remember_transaction_record_state
353
417
 
354
- status = yield
355
- raise ActiveRecord::Rollback unless status
418
+ status = yield
419
+ raise ActiveRecord::Rollback unless status
420
+ end
421
+ status
356
422
  end
357
- status
358
423
  end
359
424
 
360
425
  def trigger_transactional_callbacks? # :nodoc:
@@ -365,6 +430,13 @@ module ActiveRecord
365
430
  private
366
431
  attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
367
432
 
433
+ def init_internals
434
+ super
435
+ @_start_transaction_state = nil
436
+ @_committed_already_called = nil
437
+ @_new_record_before_last_commit = nil
438
+ end
439
+
368
440
  # Save the new record state and id of a record so it can be restored later if a transaction fails.
369
441
  def remember_transaction_record_state
370
442
  @_start_transaction_state ||= {
@@ -389,12 +461,7 @@ module ActiveRecord
389
461
  def clear_transaction_record_state
390
462
  return unless @_start_transaction_state
391
463
  @_start_transaction_state[:level] -= 1
392
- force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
393
- end
394
-
395
- # Force to clear the transaction record state.
396
- def force_clear_transaction_record_state
397
- @_start_transaction_state = nil
464
+ @_start_transaction_state = nil if @_start_transaction_state[:level] < 1
398
465
  end
399
466
 
400
467
  # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
@@ -411,8 +478,16 @@ module ActiveRecord
411
478
  end
412
479
  @mutations_from_database = nil
413
480
  @mutations_before_last_save = nil
414
- if @attributes.fetch_value(@primary_key) != restore_state[:id]
415
- @attributes.write_from_user(@primary_key, restore_state[:id])
481
+ if self.class.composite_primary_key?
482
+ if restore_state[:id] != @primary_key.map { |col| @attributes.fetch_value(col) }
483
+ @primary_key.zip(restore_state[:id]).each do |col, val|
484
+ @attributes.write_from_user(col, val)
485
+ end
486
+ end
487
+ else
488
+ if @attributes.fetch_value(@primary_key) != restore_state[:id]
489
+ @attributes.write_from_user(@primary_key, restore_state[:id])
490
+ end
416
491
  end
417
492
  freeze if restore_state[:frozen?]
418
493
  end
@@ -436,7 +511,9 @@ module ActiveRecord
436
511
  # Add the record to the current transaction so that the #after_rollback and #after_commit
437
512
  # callbacks can be called.
438
513
  def add_to_transaction(ensure_finalize = true)
439
- self.class.connection.add_transaction_record(self, ensure_finalize)
514
+ self.class.with_connection do |connection|
515
+ connection.add_transaction_record(self, ensure_finalize)
516
+ end
440
517
  end
441
518
 
442
519
  def has_transactional_callbacks?
@@ -2,10 +2,8 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Translation
5
- include ActiveModel::Translation
6
-
7
5
  # Set the lookup ancestors for ActiveModel.
8
- def lookup_ancestors #:nodoc:
6
+ def lookup_ancestors # :nodoc:
9
7
  klass = self
10
8
  classes = [klass]
11
9
  return classes if klass == ActiveRecord::Base
@@ -16,8 +14,8 @@ module ActiveRecord
16
14
  classes
17
15
  end
18
16
 
19
- # Set the i18n scope to overwrite ActiveModel.
20
- def i18n_scope #:nodoc:
17
+ # Set the i18n scope to override ActiveModel.
18
+ def i18n_scope # :nodoc:
21
19
  :activerecord
22
20
  end
23
21
  end