activerecord 4.2.0 → 6.1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1221 -796
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +267 -249
  8. data/lib/active_record/association_relation.rb +45 -7
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +172 -67
  11. data/lib/active_record/associations/association_scope.rb +105 -129
  12. data/lib/active_record/associations/belongs_to_association.rb +85 -59
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -33
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +168 -279
  22. data/lib/active_record/associations/collection_proxy.rb +263 -155
  23. data/lib/active_record/associations/foreign_association.rb +33 -0
  24. data/lib/active_record/associations/has_many_association.rb +57 -84
  25. data/lib/active_record/associations/has_many_through_association.rb +70 -82
  26. data/lib/active_record/associations/has_one_association.rb +74 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -73
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +175 -164
  32. data/lib/active_record/associations/preloader/association.rb +107 -112
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +99 -96
  35. data/lib/active_record/associations/singular_association.rb +18 -45
  36. data/lib/active_record/associations/through_association.rb +49 -24
  37. data/lib/active_record/associations.rb +1845 -1597
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -138
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -36
  46. data/lib/active_record/attribute_methods/write.rb +25 -56
  47. data/lib/active_record/attribute_methods.rb +153 -162
  48. data/lib/active_record/attributes.rb +234 -70
  49. data/lib/active_record/autosave_association.rb +157 -69
  50. data/lib/active_record/base.rb +49 -50
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +46 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +271 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +78 -161
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +499 -293
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +595 -382
  119. data/lib/active_record/connection_adapters/schema_cache.rb +191 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -389
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +488 -243
  133. data/lib/active_record/counter_cache.rb +71 -50
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +273 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +212 -94
  143. data/lib/active_record/errors.rb +225 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +11 -6
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +273 -496
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +64 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +52 -0
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +103 -95
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +298 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +685 -309
  170. data/lib/active_record/model_schema.rb +420 -113
  171. data/lib/active_record/nested_attributes.rb +265 -216
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +574 -135
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +175 -54
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +533 -216
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +485 -310
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +326 -244
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +318 -256
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +99 -84
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +139 -96
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -409
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +23 -21
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -342
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -26
  209. data/lib/active_record/scoping/default.rb +96 -82
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +133 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +366 -129
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +291 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +181 -152
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -41
  231. data/lib/active_record/type/date_time.rb +4 -38
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +33 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +65 -48
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +44 -28
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -10
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +175 -65
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  347. data/lib/active_record/attribute.rb +0 -149
  348. data/lib/active_record/attribute_decorators.rb +0 -66
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  351. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -30
  363. data/lib/active_record/type/decimal.rb +0 -40
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -55
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -36
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -101
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  374. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,35 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # See ActiveRecord::Transactions::ClassMethods for documentation.
3
5
  module Transactions
4
6
  extend ActiveSupport::Concern
5
7
  #:nodoc:
6
8
  ACTIONS = [:create, :destroy, :update]
7
- #:nodoc:
8
- CALLBACK_WARN_MESSAGE = "Currently, Active Record suppresses errors raised " \
9
- "within `after_rollback`/`after_commit` callbacks and only print them to " \
10
- "the logs. In the next version, these errors will no longer be suppressed. " \
11
- "Instead, the errors will propagate normally just like in other Active " \
12
- "Record callbacks.\n" \
13
- "\n" \
14
- "You can opt into the new behavior and remove this warning by setting:\n" \
15
- "\n" \
16
- " config.active_record.raise_in_transactional_callbacks = true\n\n"
17
9
 
18
10
  included do
19
11
  define_callbacks :commit, :rollback,
20
- terminator: ->(_, result) { result == false },
12
+ :before_commit,
21
13
  scope: [:kind, :name]
22
-
23
- mattr_accessor :raise_in_transactional_callbacks, instance_writer: false
24
- self.raise_in_transactional_callbacks = false
25
14
  end
26
15
 
27
16
  # = Active Record Transactions
28
17
  #
29
- # Transactions are protective blocks where SQL statements are only permanent
18
+ # \Transactions are protective blocks where SQL statements are only permanent
30
19
  # if they can all succeed as one atomic action. The classic example is a
31
20
  # transfer between two accounts where you can only have a deposit if the
32
- # withdrawal succeeded and vice versa. Transactions enforce the integrity of
21
+ # withdrawal succeeded and vice versa. \Transactions enforce the integrity of
33
22
  # the database and guard the data against program errors or database
34
23
  # break-downs. So basically you should use transaction blocks whenever you
35
24
  # have a number of statements that must be executed together or not at all.
@@ -49,20 +38,20 @@ module ActiveRecord
49
38
  #
50
39
  # == Different Active Record classes in a single transaction
51
40
  #
52
- # Though the transaction class method is called on some Active Record class,
41
+ # Though the #transaction class method is called on some Active Record class,
53
42
  # the objects within the transaction block need not all be instances of
54
43
  # that class. This is because transactions are per-database connection, not
55
44
  # per-model.
56
45
  #
57
46
  # In this example a +balance+ record is transactionally saved even
58
- # though +transaction+ is called on the +Account+ class:
47
+ # though #transaction is called on the +Account+ class:
59
48
  #
60
49
  # Account.transaction do
61
50
  # balance.save!
62
51
  # account.save!
63
52
  # end
64
53
  #
65
- # The +transaction+ method is also available as a model instance method.
54
+ # The #transaction method is also available as a model instance method.
66
55
  # For example, you can also do this:
67
56
  #
68
57
  # balance.transaction do
@@ -89,7 +78,8 @@ module ActiveRecord
89
78
  #
90
79
  # == +save+ and +destroy+ are automatically wrapped in a transaction
91
80
  #
92
- # Both +save+ and +destroy+ come wrapped in a transaction that ensures
81
+ # Both {#save}[rdoc-ref:Persistence#save] and
82
+ # {#destroy}[rdoc-ref:Persistence#destroy] come wrapped in a transaction that ensures
93
83
  # that whatever you do in validations or callbacks will happen under its
94
84
  # protected cover. So you can use validations to check for values that
95
85
  # the transaction depends on or you can raise exceptions in the callbacks
@@ -98,7 +88,7 @@ module ActiveRecord
98
88
  # As a consequence changes to the database are not seen outside your connection
99
89
  # until the operation is complete. For example, if you try to update the index
100
90
  # of a search engine in +after_save+ the indexer won't see the updated record.
101
- # The +after_commit+ callback is the only one that is triggered once the update
91
+ # The #after_commit callback is the only one that is triggered once the update
102
92
  # is committed. See below.
103
93
  #
104
94
  # == Exception handling and rolling back
@@ -107,11 +97,11 @@ module ActiveRecord
107
97
  # be propagated (after triggering the ROLLBACK), so you should be ready to
108
98
  # catch those in your application code.
109
99
  #
110
- # One exception is the <tt>ActiveRecord::Rollback</tt> exception, which will trigger
100
+ # One exception is the ActiveRecord::Rollback exception, which will trigger
111
101
  # a ROLLBACK when raised, but not be re-raised by the transaction block.
112
102
  #
113
- # *Warning*: one should not catch <tt>ActiveRecord::StatementInvalid</tt> exceptions
114
- # inside a transaction block. <tt>ActiveRecord::StatementInvalid</tt> exceptions indicate that an
103
+ # *Warning*: one should not catch ActiveRecord::StatementInvalid exceptions
104
+ # inside a transaction block. ActiveRecord::StatementInvalid exceptions indicate that an
115
105
  # error occurred at the database level, for example when a unique constraint
116
106
  # is violated. On some database systems, such as PostgreSQL, database errors
117
107
  # inside a transaction cause the entire transaction to become unusable
@@ -132,16 +122,16 @@ module ActiveRecord
132
122
  # # statement will cause a PostgreSQL error, even though the unique
133
123
  # # constraint is no longer violated:
134
124
  # Number.create(i: 1)
135
- # # => "PGError: ERROR: current transaction is aborted, commands
125
+ # # => "PG::Error: ERROR: current transaction is aborted, commands
136
126
  # # ignored until end of transaction block"
137
127
  # end
138
128
  #
139
129
  # One should restart the entire transaction if an
140
- # <tt>ActiveRecord::StatementInvalid</tt> occurred.
130
+ # ActiveRecord::StatementInvalid occurred.
141
131
  #
142
132
  # == Nested transactions
143
133
  #
144
- # +transaction+ calls can be nested. By default, this makes all database
134
+ # #transaction calls can be nested. By default, this makes all database
145
135
  # statements in the nested transaction block become part of the parent
146
136
  # transaction. For example, the following behavior may be surprising:
147
137
  #
@@ -153,7 +143,7 @@ module ActiveRecord
153
143
  # end
154
144
  # end
155
145
  #
156
- # creates both "Kotori" and "Nemu". Reason is the <tt>ActiveRecord::Rollback</tt>
146
+ # creates both "Kotori" and "Nemu". Reason is the ActiveRecord::Rollback
157
147
  # exception in the nested block does not issue a ROLLBACK. Since these exceptions
158
148
  # are captured in transaction blocks, the parent block does not see it and the
159
149
  # real transaction is committed.
@@ -171,34 +161,34 @@ module ActiveRecord
171
161
  # end
172
162
  # end
173
163
  #
174
- # only "Kotori" is created. This works on MySQL and PostgreSQL. SQLite3 version >= '3.6.8' also supports it.
164
+ # only "Kotori" is created.
175
165
  #
176
166
  # Most databases don't support true nested transactions. At the time of
177
167
  # writing, the only database that we're aware of that supports true nested
178
168
  # transactions, is MS-SQL. Because of this, Active Record emulates nested
179
- # transactions by using savepoints on MySQL and PostgreSQL. See
180
- # http://dev.mysql.com/doc/refman/5.6/en/savepoint.html
169
+ # transactions by using savepoints. See
170
+ # https://dev.mysql.com/doc/refman/en/savepoint.html
181
171
  # for more information about savepoints.
182
172
  #
183
- # === Callbacks
173
+ # === \Callbacks
184
174
  #
185
175
  # There are two types of callbacks associated with committing and rolling back transactions:
186
- # +after_commit+ and +after_rollback+.
176
+ # #after_commit and #after_rollback.
187
177
  #
188
- # +after_commit+ callbacks are called on every record saved or destroyed within a
189
- # transaction immediately after the transaction is committed. +after_rollback+ callbacks
178
+ # #after_commit callbacks are called on every record saved or destroyed within a
179
+ # transaction immediately after the transaction is committed. #after_rollback callbacks
190
180
  # are called on every record saved or destroyed within a transaction immediately after the
191
181
  # transaction or savepoint is rolled back.
192
182
  #
193
183
  # These callbacks are useful for interacting with other systems since you will be guaranteed
194
184
  # that the callback is only executed when the database is in a permanent state. For example,
195
- # +after_commit+ is a good spot to put in a hook to clearing a cache since clearing it from
185
+ # #after_commit is a good spot to put in a hook to clearing a cache since clearing it from
196
186
  # within a transaction could trigger the cache to be regenerated before the database is updated.
197
187
  #
198
188
  # === Caveats
199
189
  #
200
- # If you're on MySQL, then do not use DDL operations in nested transactions
201
- # blocks that are emulated with savepoints. That is, do not execute statements
190
+ # If you're on MySQL, then do not use Data Definition Language (DDL) operations in nested
191
+ # transactions blocks that are emulated with savepoints. That is, do not execute statements
202
192
  # like 'CREATE TABLE' inside such blocks. This is because MySQL automatically
203
193
  # releases all savepoints upon executing a DDL operation. When +transaction+
204
194
  # is finished and tries to release the savepoint it created earlier, a
@@ -206,18 +196,22 @@ module ActiveRecord
206
196
  # automatically released. The following example demonstrates the problem:
207
197
  #
208
198
  # Model.connection.transaction do # BEGIN
209
- # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
199
+ # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
210
200
  # Model.connection.create_table(...) # active_record_1 now automatically released
211
- # end # RELEASE savepoint active_record_1
201
+ # end # RELEASE SAVEPOINT active_record_1
212
202
  # # ^^^^ BOOM! database error!
213
203
  # end
214
204
  #
215
205
  # Note that "TRUNCATE" is also a MySQL DDL statement!
216
206
  module ClassMethods
217
- # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
218
- def transaction(options = {}, &block)
219
- # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
220
- connection.transaction(options, &block)
207
+ # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
208
+ def transaction(**options, &block)
209
+ connection.transaction(**options, &block)
210
+ end
211
+
212
+ def before_commit(*args, &block) # :nodoc:
213
+ set_options_for_callbacks!(args)
214
+ set_callback(:before_commit, :before, *args, &block)
221
215
  end
222
216
 
223
217
  # This callback is called after a record has been created, updated, or destroyed.
@@ -232,105 +226,114 @@ module ActiveRecord
232
226
  # after_commit :do_foo_bar, on: [:create, :update]
233
227
  # after_commit :do_bar_baz, on: [:update, :destroy]
234
228
  #
235
- # Note that transactional fixtures do not play well with this feature. Please
236
- # use the +test_after_commit+ gem to have these hooks fired in tests.
237
229
  def after_commit(*args, &block)
238
230
  set_options_for_callbacks!(args)
239
231
  set_callback(:commit, :after, *args, &block)
240
- unless ActiveRecord::Base.raise_in_transactional_callbacks
241
- ActiveSupport::Deprecation.warn(CALLBACK_WARN_MESSAGE)
242
- end
232
+ end
233
+
234
+ # Shortcut for <tt>after_commit :hook, on: [ :create, :update ]</tt>.
235
+ def after_save_commit(*args, &block)
236
+ set_options_for_callbacks!(args, on: [ :create, :update ])
237
+ set_callback(:commit, :after, *args, &block)
238
+ end
239
+
240
+ # Shortcut for <tt>after_commit :hook, on: :create</tt>.
241
+ def after_create_commit(*args, &block)
242
+ set_options_for_callbacks!(args, on: :create)
243
+ set_callback(:commit, :after, *args, &block)
244
+ end
245
+
246
+ # Shortcut for <tt>after_commit :hook, on: :update</tt>.
247
+ def after_update_commit(*args, &block)
248
+ set_options_for_callbacks!(args, on: :update)
249
+ set_callback(:commit, :after, *args, &block)
250
+ end
251
+
252
+ # Shortcut for <tt>after_commit :hook, on: :destroy</tt>.
253
+ def after_destroy_commit(*args, &block)
254
+ set_options_for_callbacks!(args, on: :destroy)
255
+ set_callback(:commit, :after, *args, &block)
243
256
  end
244
257
 
245
258
  # This callback is called after a create, update, or destroy are rolled back.
246
259
  #
247
- # Please check the documentation of +after_commit+ for options.
260
+ # Please check the documentation of #after_commit for options.
248
261
  def after_rollback(*args, &block)
249
262
  set_options_for_callbacks!(args)
250
263
  set_callback(:rollback, :after, *args, &block)
251
- unless ActiveRecord::Base.raise_in_transactional_callbacks
252
- ActiveSupport::Deprecation.warn(CALLBACK_WARN_MESSAGE)
253
- end
254
264
  end
255
265
 
256
266
  private
267
+ def set_options_for_callbacks!(args, enforced_options = {})
268
+ options = args.extract_options!.merge!(enforced_options)
269
+ args << options
257
270
 
258
- def set_options_for_callbacks!(args)
259
- options = args.last
260
- if options.is_a?(Hash) && options[:on]
261
- fire_on = Array(options[:on])
262
- assert_valid_transaction_action(fire_on)
263
- options[:if] = Array(options[:if])
264
- options[:if] << "transaction_include_any_action?(#{fire_on})"
271
+ if options[:on]
272
+ fire_on = Array(options[:on])
273
+ assert_valid_transaction_action(fire_on)
274
+ options[:if] = [
275
+ -> { transaction_include_any_action?(fire_on) },
276
+ *options[:if]
277
+ ]
278
+ end
265
279
  end
266
- end
267
280
 
268
- def assert_valid_transaction_action(actions)
269
- if (actions - ACTIONS).any?
270
- raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
281
+ def assert_valid_transaction_action(actions)
282
+ if (actions - ACTIONS).any?
283
+ raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
284
+ end
271
285
  end
272
- end
273
286
  end
274
287
 
275
288
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
276
- def transaction(options = {}, &block)
277
- self.class.transaction(options, &block)
289
+ def transaction(**options, &block)
290
+ self.class.transaction(**options, &block)
278
291
  end
279
292
 
280
293
  def destroy #:nodoc:
281
294
  with_transaction_returning_status { super }
282
295
  end
283
296
 
284
- def save(*) #:nodoc:
285
- rollback_active_record_state! do
286
- with_transaction_returning_status { super }
287
- end
297
+ def save(**) #:nodoc:
298
+ with_transaction_returning_status { super }
288
299
  end
289
300
 
290
- def save!(*) #:nodoc:
301
+ def save!(**) #:nodoc:
291
302
  with_transaction_returning_status { super }
292
303
  end
293
304
 
294
- def touch(*) #:nodoc:
305
+ def touch(*, **) #:nodoc:
295
306
  with_transaction_returning_status { super }
296
307
  end
297
308
 
298
- # Reset id and @new_record if the transaction rolls back.
299
- def rollback_active_record_state!
300
- remember_transaction_record_state
301
- yield
302
- rescue Exception
303
- restore_transaction_record_state
304
- raise
305
- ensure
306
- clear_transaction_record_state
309
+ def before_committed! # :nodoc:
310
+ _run_before_commit_callbacks
307
311
  end
308
312
 
309
- # Call the +after_commit+ callbacks.
313
+ # Call the #after_commit callbacks.
310
314
  #
311
315
  # Ensure that it is not called if the object was never persisted (failed create),
312
316
  # but call it after the commit of a destroyed object.
313
- def committed!(should_run_callbacks = true) #:nodoc:
314
- _run_commit_callbacks if should_run_callbacks && destroyed? || persisted?
315
- ensure
317
+ def committed!(should_run_callbacks: true) #:nodoc:
316
318
  force_clear_transaction_record_state
319
+ if should_run_callbacks
320
+ @_committed_already_called = true
321
+ _run_commit_callbacks
322
+ end
323
+ ensure
324
+ @_committed_already_called = @_trigger_update_callback = @_trigger_destroy_callback = false
317
325
  end
318
326
 
319
- # Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record
327
+ # Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
320
328
  # state should be rolled back to the beginning or just to the last savepoint.
321
- def rolledback!(force_restore_state = false, should_run_callbacks = true) #:nodoc:
322
- _run_rollback_callbacks if should_run_callbacks
329
+ def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
330
+ if should_run_callbacks
331
+ _run_rollback_callbacks
332
+ end
323
333
  ensure
324
334
  restore_transaction_record_state(force_restore_state)
325
335
  clear_transaction_record_state
326
- end
327
-
328
- # Add the record to the current transaction so that the +after_rollback+ and +after_commit+ callbacks
329
- # can be called.
330
- def add_to_transaction
331
- if self.class.connection.add_transaction_record(self)
332
- remember_transaction_record_state
333
- end
336
+ @_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state
334
337
  end
335
338
 
336
339
  # Executes +method+ within a transaction and captures its return value as a
@@ -341,77 +344,103 @@ module ActiveRecord
341
344
  # instance.
342
345
  def with_transaction_returning_status
343
346
  status = nil
344
- self.class.transaction do
345
- add_to_transaction
346
- begin
347
- status = yield
348
- rescue ActiveRecord::Rollback
349
- clear_transaction_record_state
350
- status = nil
351
- end
347
+ connection = self.class.connection
348
+ ensure_finalize = !connection.transaction_open?
349
+
350
+ connection.transaction do
351
+ add_to_transaction(ensure_finalize || has_transactional_callbacks?)
352
+ remember_transaction_record_state
352
353
 
354
+ status = yield
353
355
  raise ActiveRecord::Rollback unless status
354
356
  end
355
357
  status
356
358
  end
357
359
 
358
- protected
360
+ def trigger_transactional_callbacks? # :nodoc:
361
+ (@_new_record_before_last_commit || _trigger_update_callback) && persisted? ||
362
+ _trigger_destroy_callback && destroyed?
363
+ end
364
+
365
+ private
366
+ attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
367
+
368
+ # Save the new record state and id of a record so it can be restored later if a transaction fails.
369
+ def remember_transaction_record_state
370
+ @_start_transaction_state ||= {
371
+ id: id,
372
+ new_record: @new_record,
373
+ previously_new_record: @previously_new_record,
374
+ destroyed: @destroyed,
375
+ attributes: @attributes,
376
+ frozen?: frozen?,
377
+ level: 0
378
+ }
379
+ @_start_transaction_state[:level] += 1
359
380
 
360
- # Save the new record state and id of a record so it can be restored later if a transaction fails.
361
- def remember_transaction_record_state #:nodoc:
362
- @_start_transaction_state[:id] = id
363
- unless @_start_transaction_state.include?(:new_record)
364
- @_start_transaction_state[:new_record] = @new_record
381
+ if _committed_already_called
382
+ @_new_record_before_last_commit = false
383
+ else
384
+ @_new_record_before_last_commit = @_start_transaction_state[:new_record]
385
+ end
365
386
  end
366
- unless @_start_transaction_state.include?(:destroyed)
367
- @_start_transaction_state[:destroyed] = @destroyed
387
+
388
+ # Clear the new record state and id of a record.
389
+ def clear_transaction_record_state
390
+ return unless @_start_transaction_state
391
+ @_start_transaction_state[:level] -= 1
392
+ force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
368
393
  end
369
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
370
- @_start_transaction_state[:frozen?] = frozen?
371
- end
372
394
 
373
- # Clear the new record state and id of a record.
374
- def clear_transaction_record_state #:nodoc:
375
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
376
- force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
377
- end
395
+ # Force to clear the transaction record state.
396
+ def force_clear_transaction_record_state
397
+ @_start_transaction_state = nil
398
+ end
378
399
 
379
- # Force to clear the transaction record state.
380
- def force_clear_transaction_record_state #:nodoc:
381
- @_start_transaction_state.clear
382
- end
400
+ # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
401
+ def restore_transaction_record_state(force_restore_state = false)
402
+ if restore_state = @_start_transaction_state
403
+ if force_restore_state || restore_state[:level] <= 1
404
+ @new_record = restore_state[:new_record]
405
+ @previously_new_record = restore_state[:previously_new_record]
406
+ @destroyed = restore_state[:destroyed]
407
+ @attributes = restore_state[:attributes].map do |attr|
408
+ value = @attributes.fetch_value(attr.name)
409
+ attr = attr.with_value_from_user(value) if attr.value != value
410
+ attr
411
+ end
412
+ @mutations_from_database = nil
413
+ @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])
416
+ end
417
+ freeze if restore_state[:frozen?]
418
+ end
419
+ end
420
+ end
383
421
 
384
- # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
385
- def restore_transaction_record_state(force = false) #:nodoc:
386
- unless @_start_transaction_state.empty?
387
- transaction_level = (@_start_transaction_state[:level] || 0) - 1
388
- if transaction_level < 1 || force
389
- restore_state = @_start_transaction_state
390
- thaw unless restore_state[:frozen?]
391
- @new_record = restore_state[:new_record]
392
- @destroyed = restore_state[:destroyed]
393
- write_attribute(self.class.primary_key, restore_state[:id])
422
+ # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
423
+ def transaction_include_any_action?(actions)
424
+ actions.any? do |action|
425
+ case action
426
+ when :create
427
+ persisted? && @_new_record_before_last_commit
428
+ when :update
429
+ !(@_new_record_before_last_commit || destroyed?) && _trigger_update_callback
430
+ when :destroy
431
+ _trigger_destroy_callback
432
+ end
394
433
  end
395
434
  end
396
- end
397
435
 
398
- # Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
399
- def transaction_record_state(state) #:nodoc:
400
- @_start_transaction_state[state]
401
- end
436
+ # Add the record to the current transaction so that the #after_rollback and #after_commit
437
+ # callbacks can be called.
438
+ def add_to_transaction(ensure_finalize = true)
439
+ self.class.connection.add_transaction_record(self, ensure_finalize)
440
+ end
402
441
 
403
- # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
404
- def transaction_include_any_action?(actions) #:nodoc:
405
- actions.any? do |action|
406
- case action
407
- when :create
408
- transaction_record_state(:new_record)
409
- when :destroy
410
- destroyed?
411
- when :update
412
- !(transaction_record_state(:new_record) || destroyed?)
413
- end
442
+ def has_transactional_callbacks?
443
+ !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
414
444
  end
415
- end
416
445
  end
417
446
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Translation
3
5
  include ActiveModel::Translation
@@ -8,7 +10,7 @@ module ActiveRecord
8
10
  classes = [klass]
9
11
  return classes if klass == ActiveRecord::Base
10
12
 
11
- while klass != klass.base_class
13
+ while !klass.base_class?
12
14
  classes << klass = klass.superclass
13
15
  end
14
16
  classes
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/registry"
4
+
5
+ module ActiveRecord
6
+ # :stopdoc:
7
+ module Type
8
+ class AdapterSpecificRegistry < ActiveModel::Type::Registry
9
+ def add_modifier(options, klass, **args)
10
+ registrations << DecorationRegistration.new(options, klass, **args)
11
+ end
12
+
13
+ private
14
+ def registration_klass
15
+ Registration
16
+ end
17
+
18
+ def find_registration(symbol, *args, **kwargs)
19
+ registrations
20
+ .select { |registration| registration.matches?(symbol, *args, **kwargs) }
21
+ .max
22
+ end
23
+ end
24
+
25
+ class Registration
26
+ def initialize(name, block, adapter: nil, override: nil)
27
+ @name = name
28
+ @block = block
29
+ @adapter = adapter
30
+ @override = override
31
+ end
32
+
33
+ def call(_registry, *args, adapter: nil, **kwargs)
34
+ if kwargs.any? # https://bugs.ruby-lang.org/issues/10856
35
+ block.call(*args, **kwargs)
36
+ else
37
+ block.call(*args)
38
+ end
39
+ end
40
+
41
+ def matches?(type_name, *args, **kwargs)
42
+ type_name == name && matches_adapter?(**kwargs)
43
+ end
44
+
45
+ def <=>(other)
46
+ if conflicts_with?(other)
47
+ raise TypeConflictError.new("Type #{name} was registered for all
48
+ adapters, but shadows a native type with
49
+ the same name for #{other.adapter}".squish)
50
+ end
51
+ priority <=> other.priority
52
+ end
53
+
54
+ protected
55
+ attr_reader :name, :block, :adapter, :override
56
+
57
+ def priority
58
+ result = 0
59
+ if adapter
60
+ result |= 1
61
+ end
62
+ if override
63
+ result |= 2
64
+ end
65
+ result
66
+ end
67
+
68
+ def priority_except_adapter
69
+ priority & 0b111111100
70
+ end
71
+
72
+ private
73
+ def matches_adapter?(adapter: nil, **)
74
+ (self.adapter.nil? || adapter == self.adapter)
75
+ end
76
+
77
+ def conflicts_with?(other)
78
+ same_priority_except_adapter?(other) &&
79
+ has_adapter_conflict?(other)
80
+ end
81
+
82
+ def same_priority_except_adapter?(other)
83
+ priority_except_adapter == other.priority_except_adapter
84
+ end
85
+
86
+ def has_adapter_conflict?(other)
87
+ (override.nil? && other.adapter) ||
88
+ (adapter && other.override.nil?)
89
+ end
90
+ end
91
+
92
+ class DecorationRegistration < Registration
93
+ def initialize(options, klass, adapter: nil)
94
+ @options = options
95
+ @klass = klass
96
+ @adapter = adapter
97
+ end
98
+
99
+ def call(registry, *args, **kwargs)
100
+ subtype = registry.lookup(*args, **kwargs.except(*options.keys))
101
+ klass.new(subtype)
102
+ end
103
+
104
+ def matches?(*args, **kwargs)
105
+ matches_adapter?(**kwargs) && matches_options?(**kwargs)
106
+ end
107
+
108
+ def priority
109
+ super | 4
110
+ end
111
+
112
+ private
113
+ attr_reader :options, :klass
114
+
115
+ def matches_options?(**kwargs)
116
+ options.all? do |key, value|
117
+ kwargs[key] == value
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ class TypeConflictError < StandardError
124
+ end
125
+ # :startdoc:
126
+ end