activerecord 3.2.6 → 6.0.0

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

Potentially problematic release.


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

Files changed (371) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +611 -6417
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +44 -47
  5. data/examples/performance.rb +79 -71
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +268 -238
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +173 -81
  11. data/lib/active_record/associations/association_scope.rb +124 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -38
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +11 -9
  14. data/lib/active_record/associations/builder/association.rb +113 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +105 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +53 -56
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +98 -41
  18. data/lib/active_record/associations/builder/has_many.rb +11 -63
  19. data/lib/active_record/associations/builder/has_one.rb +47 -45
  20. data/lib/active_record/associations/builder/singular_association.rb +30 -18
  21. data/lib/active_record/associations/collection_association.rb +217 -295
  22. data/lib/active_record/associations/collection_proxy.rb +1074 -77
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +78 -50
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -61
  26. data/lib/active_record/associations/has_one_association.rb +75 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +45 -119
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +208 -164
  32. data/lib/active_record/associations/preloader/association.rb +93 -87
  33. data/lib/active_record/associations/preloader/through_association.rb +87 -38
  34. data/lib/active_record/associations/preloader.rb +134 -110
  35. data/lib/active_record/associations/singular_association.rb +19 -24
  36. data/lib/active_record/associations/through_association.rb +61 -27
  37. data/lib/active_record/associations.rb +1766 -1505
  38. data/lib/active_record/attribute_assignment.rb +57 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +58 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +187 -67
  42. data/lib/active_record/attribute_methods/primary_key.rb +100 -78
  43. data/lib/active_record/attribute_methods/query.rb +10 -8
  44. data/lib/active_record/attribute_methods/read.rb +29 -118
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -72
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -42
  47. data/lib/active_record/attribute_methods/write.rb +36 -44
  48. data/lib/active_record/attribute_methods.rb +306 -161
  49. data/lib/active_record/attributes.rb +279 -0
  50. data/lib/active_record/autosave_association.rb +324 -238
  51. data/lib/active_record/base.rb +114 -507
  52. data/lib/active_record/callbacks.rb +147 -83
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +962 -279
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +32 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +331 -209
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -23
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +201 -65
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +510 -289
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1182 -313
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +585 -120
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +610 -463
  68. data/lib/active_record/connection_adapters/column.rb +58 -233
  69. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +75 -207
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +695 -1052
  116. data/lib/active_record/connection_adapters/schema_cache.rb +115 -24
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +528 -26
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +267 -0
  128. data/lib/active_record/core.rb +599 -0
  129. data/lib/active_record/counter_cache.rb +177 -103
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +107 -64
  136. data/lib/active_record/enum.rb +274 -0
  137. data/lib/active_record/errors.rb +254 -61
  138. data/lib/active_record/explain.rb +35 -70
  139. data/lib/active_record/explain_registry.rb +32 -0
  140. data/lib/active_record/explain_subscriber.rb +18 -8
  141. data/lib/active_record/fixture_set/file.rb +82 -0
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +291 -475
  147. data/lib/active_record/gem_version.rb +17 -0
  148. data/lib/active_record/inheritance.rb +219 -100
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +175 -17
  151. data/lib/active_record/internal_metadata.rb +53 -0
  152. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  153. data/lib/active_record/locale/en.yml +9 -1
  154. data/lib/active_record/locking/optimistic.rb +106 -92
  155. data/lib/active_record/locking/pessimistic.rb +23 -11
  156. data/lib/active_record/log_subscriber.rb +80 -30
  157. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  158. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  159. data/lib/active_record/middleware/database_selector.rb +75 -0
  160. data/lib/active_record/migration/command_recorder.rb +235 -56
  161. data/lib/active_record/migration/compatibility.rb +244 -0
  162. data/lib/active_record/migration/join_table.rb +17 -0
  163. data/lib/active_record/migration.rb +917 -301
  164. data/lib/active_record/model_schema.rb +351 -175
  165. data/lib/active_record/nested_attributes.rb +366 -235
  166. data/lib/active_record/no_touching.rb +65 -0
  167. data/lib/active_record/null_relation.rb +68 -0
  168. data/lib/active_record/persistence.rb +761 -166
  169. data/lib/active_record/query_cache.rb +22 -44
  170. data/lib/active_record/querying.rb +55 -31
  171. data/lib/active_record/railtie.rb +185 -47
  172. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  173. data/lib/active_record/railties/console_sandbox.rb +5 -4
  174. data/lib/active_record/railties/controller_runtime.rb +35 -33
  175. data/lib/active_record/railties/databases.rake +366 -463
  176. data/lib/active_record/readonly_attributes.rb +4 -6
  177. data/lib/active_record/reflection.rb +736 -228
  178. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  179. data/lib/active_record/relation/batches.rb +252 -52
  180. data/lib/active_record/relation/calculations.rb +340 -270
  181. data/lib/active_record/relation/delegation.rb +117 -36
  182. data/lib/active_record/relation/finder_methods.rb +439 -286
  183. data/lib/active_record/relation/from_clause.rb +26 -0
  184. data/lib/active_record/relation/merger.rb +184 -0
  185. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  186. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  187. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  188. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  189. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  190. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  191. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder.rb +131 -39
  193. data/lib/active_record/relation/query_attribute.rb +50 -0
  194. data/lib/active_record/relation/query_methods.rb +1163 -221
  195. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  196. data/lib/active_record/relation/spawn_methods.rb +49 -120
  197. data/lib/active_record/relation/where_clause.rb +190 -0
  198. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  199. data/lib/active_record/relation.rb +671 -349
  200. data/lib/active_record/result.rb +149 -15
  201. data/lib/active_record/runtime_registry.rb +24 -0
  202. data/lib/active_record/sanitization.rb +153 -133
  203. data/lib/active_record/schema.rb +22 -19
  204. data/lib/active_record/schema_dumper.rb +178 -112
  205. data/lib/active_record/schema_migration.rb +60 -0
  206. data/lib/active_record/scoping/default.rb +107 -98
  207. data/lib/active_record/scoping/named.rb +130 -115
  208. data/lib/active_record/scoping.rb +77 -123
  209. data/lib/active_record/secure_token.rb +40 -0
  210. data/lib/active_record/serialization.rb +10 -6
  211. data/lib/active_record/statement_cache.rb +148 -0
  212. data/lib/active_record/store.rb +256 -16
  213. data/lib/active_record/suppressor.rb +61 -0
  214. data/lib/active_record/table_metadata.rb +75 -0
  215. data/lib/active_record/tasks/database_tasks.rb +506 -0
  216. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  217. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  218. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  219. data/lib/active_record/test_databases.rb +23 -0
  220. data/lib/active_record/test_fixtures.rb +224 -0
  221. data/lib/active_record/timestamp.rb +93 -39
  222. data/lib/active_record/touch_later.rb +66 -0
  223. data/lib/active_record/transactions.rb +260 -129
  224. data/lib/active_record/translation.rb +3 -1
  225. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  226. data/lib/active_record/type/date.rb +9 -0
  227. data/lib/active_record/type/date_time.rb +9 -0
  228. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  229. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  230. data/lib/active_record/type/internal/timezone.rb +17 -0
  231. data/lib/active_record/type/json.rb +30 -0
  232. data/lib/active_record/type/serialized.rb +71 -0
  233. data/lib/active_record/type/text.rb +11 -0
  234. data/lib/active_record/type/time.rb +21 -0
  235. data/lib/active_record/type/type_map.rb +62 -0
  236. data/lib/active_record/type/unsigned_integer.rb +17 -0
  237. data/lib/active_record/type.rb +78 -0
  238. data/lib/active_record/type_caster/connection.rb +34 -0
  239. data/lib/active_record/type_caster/map.rb +20 -0
  240. data/lib/active_record/type_caster.rb +9 -0
  241. data/lib/active_record/validations/absence.rb +25 -0
  242. data/lib/active_record/validations/associated.rb +35 -18
  243. data/lib/active_record/validations/length.rb +26 -0
  244. data/lib/active_record/validations/presence.rb +68 -0
  245. data/lib/active_record/validations/uniqueness.rb +123 -77
  246. data/lib/active_record/validations.rb +54 -43
  247. data/lib/active_record/version.rb +7 -7
  248. data/lib/active_record.rb +97 -49
  249. data/lib/arel/alias_predication.rb +9 -0
  250. data/lib/arel/attributes/attribute.rb +37 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/collectors/bind.rb +24 -0
  253. data/lib/arel/collectors/composite.rb +31 -0
  254. data/lib/arel/collectors/plain_string.rb +20 -0
  255. data/lib/arel/collectors/sql_string.rb +20 -0
  256. data/lib/arel/collectors/substitute_binds.rb +28 -0
  257. data/lib/arel/crud.rb +42 -0
  258. data/lib/arel/delete_manager.rb +18 -0
  259. data/lib/arel/errors.rb +9 -0
  260. data/lib/arel/expressions.rb +29 -0
  261. data/lib/arel/factory_methods.rb +49 -0
  262. data/lib/arel/insert_manager.rb +49 -0
  263. data/lib/arel/math.rb +45 -0
  264. data/lib/arel/nodes/and.rb +32 -0
  265. data/lib/arel/nodes/ascending.rb +23 -0
  266. data/lib/arel/nodes/binary.rb +52 -0
  267. data/lib/arel/nodes/bind_param.rb +36 -0
  268. data/lib/arel/nodes/case.rb +55 -0
  269. data/lib/arel/nodes/casted.rb +50 -0
  270. data/lib/arel/nodes/comment.rb +29 -0
  271. data/lib/arel/nodes/count.rb +12 -0
  272. data/lib/arel/nodes/delete_statement.rb +45 -0
  273. data/lib/arel/nodes/descending.rb +23 -0
  274. data/lib/arel/nodes/equality.rb +18 -0
  275. data/lib/arel/nodes/extract.rb +24 -0
  276. data/lib/arel/nodes/false.rb +16 -0
  277. data/lib/arel/nodes/full_outer_join.rb +8 -0
  278. data/lib/arel/nodes/function.rb +44 -0
  279. data/lib/arel/nodes/grouping.rb +8 -0
  280. data/lib/arel/nodes/in.rb +8 -0
  281. data/lib/arel/nodes/infix_operation.rb +80 -0
  282. data/lib/arel/nodes/inner_join.rb +8 -0
  283. data/lib/arel/nodes/insert_statement.rb +37 -0
  284. data/lib/arel/nodes/join_source.rb +20 -0
  285. data/lib/arel/nodes/matches.rb +18 -0
  286. data/lib/arel/nodes/named_function.rb +23 -0
  287. data/lib/arel/nodes/node.rb +50 -0
  288. data/lib/arel/nodes/node_expression.rb +13 -0
  289. data/lib/arel/nodes/outer_join.rb +8 -0
  290. data/lib/arel/nodes/over.rb +15 -0
  291. data/lib/arel/nodes/regexp.rb +16 -0
  292. data/lib/arel/nodes/right_outer_join.rb +8 -0
  293. data/lib/arel/nodes/select_core.rb +67 -0
  294. data/lib/arel/nodes/select_statement.rb +41 -0
  295. data/lib/arel/nodes/sql_literal.rb +16 -0
  296. data/lib/arel/nodes/string_join.rb +11 -0
  297. data/lib/arel/nodes/table_alias.rb +27 -0
  298. data/lib/arel/nodes/terminal.rb +16 -0
  299. data/lib/arel/nodes/true.rb +16 -0
  300. data/lib/arel/nodes/unary.rb +45 -0
  301. data/lib/arel/nodes/unary_operation.rb +20 -0
  302. data/lib/arel/nodes/unqualified_column.rb +22 -0
  303. data/lib/arel/nodes/update_statement.rb +41 -0
  304. data/lib/arel/nodes/values_list.rb +9 -0
  305. data/lib/arel/nodes/window.rb +126 -0
  306. data/lib/arel/nodes/with.rb +11 -0
  307. data/lib/arel/nodes.rb +68 -0
  308. data/lib/arel/order_predications.rb +13 -0
  309. data/lib/arel/predications.rb +257 -0
  310. data/lib/arel/select_manager.rb +271 -0
  311. data/lib/arel/table.rb +110 -0
  312. data/lib/arel/tree_manager.rb +72 -0
  313. data/lib/arel/update_manager.rb +34 -0
  314. data/lib/arel/visitors/depth_first.rb +204 -0
  315. data/lib/arel/visitors/dot.rb +297 -0
  316. data/lib/arel/visitors/ibm_db.rb +34 -0
  317. data/lib/arel/visitors/informix.rb +62 -0
  318. data/lib/arel/visitors/mssql.rb +157 -0
  319. data/lib/arel/visitors/mysql.rb +83 -0
  320. data/lib/arel/visitors/oracle.rb +159 -0
  321. data/lib/arel/visitors/oracle12.rb +66 -0
  322. data/lib/arel/visitors/postgresql.rb +110 -0
  323. data/lib/arel/visitors/sqlite.rb +39 -0
  324. data/lib/arel/visitors/to_sql.rb +889 -0
  325. data/lib/arel/visitors/visitor.rb +46 -0
  326. data/lib/arel/visitors/where_sql.rb +23 -0
  327. data/lib/arel/visitors.rb +20 -0
  328. data/lib/arel/window_predications.rb +9 -0
  329. data/lib/arel.rb +51 -0
  330. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  331. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +59 -9
  333. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  334. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  335. data/lib/rails/generators/active_record/migration.rb +41 -8
  336. data/lib/rails/generators/active_record/model/model_generator.rb +24 -22
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  339. data/lib/rails/generators/active_record.rb +10 -16
  340. metadata +285 -149
  341. data/examples/associations.png +0 -0
  342. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  343. data/lib/active_record/associations/join_helper.rb +0 -55
  344. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  345. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  346. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  347. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  348. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  349. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  350. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  351. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  352. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  353. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -188
  354. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -426
  355. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -579
  356. data/lib/active_record/dynamic_finder_match.rb +0 -68
  357. data/lib/active_record/dynamic_scope_match.rb +0 -23
  358. data/lib/active_record/fixtures/file.rb +0 -65
  359. data/lib/active_record/identity_map.rb +0 -162
  360. data/lib/active_record/observer.rb +0 -121
  361. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  362. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  363. data/lib/active_record/session_store.rb +0 -358
  364. data/lib/active_record/test_case.rb +0 -73
  365. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  366. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  367. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  368. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  369. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  370. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  371. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ # = Active Record Touch Later
5
+ module TouchLater # :nodoc:
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_commit_without_transaction_enrollment :touch_deferred_attributes
10
+ end
11
+
12
+ def touch_later(*names) # :nodoc:
13
+ unless persisted?
14
+ raise ActiveRecordError, <<-MSG.squish
15
+ cannot touch on a new or destroyed record object. Consider using
16
+ persisted?, new_record?, or destroyed? before touching
17
+ MSG
18
+ end
19
+
20
+ @_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
21
+ @_defer_touch_attrs |= names
22
+ @_touch_time = current_time_from_proper_timezone
23
+
24
+ surreptitiously_touch @_defer_touch_attrs
25
+ add_to_transaction
26
+ @_new_record_before_last_commit ||= false
27
+
28
+ # touch the parents as we are not calling the after_save callbacks
29
+ self.class.reflect_on_all_associations(:belongs_to).each do |r|
30
+ if touch = r.options[:touch]
31
+ ActiveRecord::Associations::Builder::BelongsTo.touch_record(self, changes_to_save, r.foreign_key, r.name, touch, :touch_later)
32
+ end
33
+ end
34
+ end
35
+
36
+ def touch(*names, time: nil) # :nodoc:
37
+ if has_defer_touch_attrs?
38
+ names |= @_defer_touch_attrs
39
+ end
40
+ super(*names, time: time)
41
+ end
42
+
43
+ private
44
+
45
+ def surreptitiously_touch(attrs)
46
+ attrs.each { |attr| write_attribute attr, @_touch_time }
47
+ clear_attribute_changes attrs
48
+ end
49
+
50
+ def touch_deferred_attributes
51
+ if has_defer_touch_attrs? && persisted?
52
+ @_skip_dirty_tracking = true
53
+ touch(*@_defer_touch_attrs, time: @_touch_time)
54
+ @_defer_touch_attrs, @_touch_time = nil, nil
55
+ end
56
+ end
57
+
58
+ def has_defer_touch_attrs?
59
+ defined?(@_defer_touch_attrs) && @_defer_touch_attrs.present?
60
+ end
61
+
62
+ def belongs_to_touch_method
63
+ :touch_later
64
+ end
65
+ end
66
+ end
@@ -1,23 +1,27 @@
1
- require 'thread'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
4
  # See ActiveRecord::Transactions::ClassMethods for documentation.
5
5
  module Transactions
6
6
  extend ActiveSupport::Concern
7
-
8
- class TransactionError < ActiveRecordError # :nodoc:
9
- end
7
+ #:nodoc:
8
+ ACTIONS = [:create, :destroy, :update]
10
9
 
11
10
  included do
12
- define_callbacks :commit, :rollback, :terminator => "result == false", :scope => [:kind, :name]
11
+ define_callbacks :commit, :rollback,
12
+ :before_commit,
13
+ :before_commit_without_transaction_enrollment,
14
+ :commit_without_transaction_enrollment,
15
+ :rollback_without_transaction_enrollment,
16
+ scope: [:kind, :name]
13
17
  end
14
18
 
15
19
  # = Active Record Transactions
16
20
  #
17
- # Transactions are protective blocks where SQL statements are only permanent
21
+ # \Transactions are protective blocks where SQL statements are only permanent
18
22
  # if they can all succeed as one atomic action. The classic example is a
19
23
  # transfer between two accounts where you can only have a deposit if the
20
- # withdrawal succeeded and vice versa. Transactions enforce the integrity of
24
+ # withdrawal succeeded and vice versa. \Transactions enforce the integrity of
21
25
  # the database and guard the data against program errors or database
22
26
  # break-downs. So basically you should use transaction blocks whenever you
23
27
  # have a number of statements that must be executed together or not at all.
@@ -37,20 +41,20 @@ module ActiveRecord
37
41
  #
38
42
  # == Different Active Record classes in a single transaction
39
43
  #
40
- # Though the transaction class method is called on some Active Record class,
44
+ # Though the #transaction class method is called on some Active Record class,
41
45
  # the objects within the transaction block need not all be instances of
42
46
  # that class. This is because transactions are per-database connection, not
43
47
  # per-model.
44
48
  #
45
49
  # In this example a +balance+ record is transactionally saved even
46
- # though +transaction+ is called on the +Account+ class:
50
+ # though #transaction is called on the +Account+ class:
47
51
  #
48
52
  # Account.transaction do
49
53
  # balance.save!
50
54
  # account.save!
51
55
  # end
52
56
  #
53
- # The +transaction+ method is also available as a model instance method.
57
+ # The #transaction method is also available as a model instance method.
54
58
  # For example, you can also do this:
55
59
  #
56
60
  # balance.transaction do
@@ -77,7 +81,8 @@ module ActiveRecord
77
81
  #
78
82
  # == +save+ and +destroy+ are automatically wrapped in a transaction
79
83
  #
80
- # Both +save+ and +destroy+ come wrapped in a transaction that ensures
84
+ # Both {#save}[rdoc-ref:Persistence#save] and
85
+ # {#destroy}[rdoc-ref:Persistence#destroy] come wrapped in a transaction that ensures
81
86
  # that whatever you do in validations or callbacks will happen under its
82
87
  # protected cover. So you can use validations to check for values that
83
88
  # the transaction depends on or you can raise exceptions in the callbacks
@@ -86,7 +91,7 @@ module ActiveRecord
86
91
  # As a consequence changes to the database are not seen outside your connection
87
92
  # until the operation is complete. For example, if you try to update the index
88
93
  # of a search engine in +after_save+ the indexer won't see the updated record.
89
- # The +after_commit+ callback is the only one that is triggered once the update
94
+ # The #after_commit callback is the only one that is triggered once the update
90
95
  # is committed. See below.
91
96
  #
92
97
  # == Exception handling and rolling back
@@ -95,11 +100,11 @@ module ActiveRecord
95
100
  # be propagated (after triggering the ROLLBACK), so you should be ready to
96
101
  # catch those in your application code.
97
102
  #
98
- # One exception is the <tt>ActiveRecord::Rollback</tt> exception, which will trigger
103
+ # One exception is the ActiveRecord::Rollback exception, which will trigger
99
104
  # a ROLLBACK when raised, but not be re-raised by the transaction block.
100
105
  #
101
- # *Warning*: one should not catch <tt>ActiveRecord::StatementInvalid</tt> exceptions
102
- # inside a transaction block. <tt>ActiveRecord::StatementInvalid</tt> exceptions indicate that an
106
+ # *Warning*: one should not catch ActiveRecord::StatementInvalid exceptions
107
+ # inside a transaction block. ActiveRecord::StatementInvalid exceptions indicate that an
103
108
  # error occurred at the database level, for example when a unique constraint
104
109
  # is violated. On some database systems, such as PostgreSQL, database errors
105
110
  # inside a transaction cause the entire transaction to become unusable
@@ -108,10 +113,10 @@ module ActiveRecord
108
113
  #
109
114
  # # Suppose that we have a Number model with a unique column called 'i'.
110
115
  # Number.transaction do
111
- # Number.create(:i => 0)
116
+ # Number.create(i: 0)
112
117
  # begin
113
118
  # # This will raise a unique constraint error...
114
- # Number.create(:i => 0)
119
+ # Number.create(i: 0)
115
120
  # rescue ActiveRecord::StatementInvalid
116
121
  # # ...which we ignore.
117
122
  # end
@@ -119,74 +124,74 @@ module ActiveRecord
119
124
  # # On PostgreSQL, the transaction is now unusable. The following
120
125
  # # statement will cause a PostgreSQL error, even though the unique
121
126
  # # constraint is no longer violated:
122
- # Number.create(:i => 1)
123
- # # => "PGError: ERROR: current transaction is aborted, commands
127
+ # Number.create(i: 1)
128
+ # # => "PG::Error: ERROR: current transaction is aborted, commands
124
129
  # # ignored until end of transaction block"
125
130
  # end
126
131
  #
127
132
  # One should restart the entire transaction if an
128
- # <tt>ActiveRecord::StatementInvalid</tt> occurred.
133
+ # ActiveRecord::StatementInvalid occurred.
129
134
  #
130
135
  # == Nested transactions
131
136
  #
132
- # +transaction+ calls can be nested. By default, this makes all database
137
+ # #transaction calls can be nested. By default, this makes all database
133
138
  # statements in the nested transaction block become part of the parent
134
139
  # transaction. For example, the following behavior may be surprising:
135
140
  #
136
141
  # User.transaction do
137
- # User.create(:username => 'Kotori')
142
+ # User.create(username: 'Kotori')
138
143
  # User.transaction do
139
- # User.create(:username => 'Nemu')
144
+ # User.create(username: 'Nemu')
140
145
  # raise ActiveRecord::Rollback
141
146
  # end
142
147
  # end
143
148
  #
144
- # creates both "Kotori" and "Nemu". Reason is the <tt>ActiveRecord::Rollback</tt>
149
+ # creates both "Kotori" and "Nemu". Reason is the ActiveRecord::Rollback
145
150
  # exception in the nested block does not issue a ROLLBACK. Since these exceptions
146
151
  # are captured in transaction blocks, the parent block does not see it and the
147
152
  # real transaction is committed.
148
153
  #
149
154
  # In order to get a ROLLBACK for the nested transaction you may ask for a real
150
- # sub-transaction by passing <tt>:requires_new => true</tt>. If anything goes wrong,
155
+ # sub-transaction by passing <tt>requires_new: true</tt>. If anything goes wrong,
151
156
  # the database rolls back to the beginning of the sub-transaction without rolling
152
157
  # back the parent transaction. If we add it to the previous example:
153
158
  #
154
159
  # User.transaction do
155
- # User.create(:username => 'Kotori')
156
- # User.transaction(:requires_new => true) do
157
- # User.create(:username => 'Nemu')
160
+ # User.create(username: 'Kotori')
161
+ # User.transaction(requires_new: true) do
162
+ # User.create(username: 'Nemu')
158
163
  # raise ActiveRecord::Rollback
159
164
  # end
160
165
  # end
161
166
  #
162
- # only "Kotori" is created. (This works on MySQL and PostgreSQL, but not on SQLite3.)
167
+ # only "Kotori" is created. This works on MySQL and PostgreSQL. SQLite3 version >= '3.6.8' also supports it.
163
168
  #
164
169
  # Most databases don't support true nested transactions. At the time of
165
170
  # writing, the only database that we're aware of that supports true nested
166
171
  # transactions, is MS-SQL. Because of this, Active Record emulates nested
167
172
  # transactions by using savepoints on MySQL and PostgreSQL. See
168
- # http://dev.mysql.com/doc/refman/5.0/en/savepoint.html
173
+ # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
169
174
  # for more information about savepoints.
170
175
  #
171
- # === Callbacks
176
+ # === \Callbacks
172
177
  #
173
178
  # There are two types of callbacks associated with committing and rolling back transactions:
174
- # +after_commit+ and +after_rollback+.
179
+ # #after_commit and #after_rollback.
175
180
  #
176
- # +after_commit+ callbacks are called on every record saved or destroyed within a
177
- # transaction immediately after the transaction is committed. +after_rollback+ callbacks
181
+ # #after_commit callbacks are called on every record saved or destroyed within a
182
+ # transaction immediately after the transaction is committed. #after_rollback callbacks
178
183
  # are called on every record saved or destroyed within a transaction immediately after the
179
184
  # transaction or savepoint is rolled back.
180
185
  #
181
186
  # These callbacks are useful for interacting with other systems since you will be guaranteed
182
187
  # that the callback is only executed when the database is in a permanent state. For example,
183
- # +after_commit+ is a good spot to put in a hook to clearing a cache since clearing it from
188
+ # #after_commit is a good spot to put in a hook to clearing a cache since clearing it from
184
189
  # within a transaction could trigger the cache to be regenerated before the database is updated.
185
190
  #
186
191
  # === Caveats
187
192
  #
188
- # If you're on MySQL, then do not use DDL operations in nested transactions
189
- # blocks that are emulated with savepoints. That is, do not execute statements
193
+ # If you're on MySQL, then do not use Data Definition Language (DDL) operations in nested
194
+ # transactions blocks that are emulated with savepoints. That is, do not execute statements
190
195
  # like 'CREATE TABLE' inside such blocks. This is because MySQL automatically
191
196
  # releases all savepoints upon executing a DDL operation. When +transaction+
192
197
  # is finished and tries to release the savepoint it created earlier, a
@@ -194,37 +199,107 @@ module ActiveRecord
194
199
  # automatically released. The following example demonstrates the problem:
195
200
  #
196
201
  # Model.connection.transaction do # BEGIN
197
- # Model.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1
202
+ # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
198
203
  # Model.connection.create_table(...) # active_record_1 now automatically released
199
- # end # RELEASE savepoint active_record_1
204
+ # end # RELEASE SAVEPOINT active_record_1
200
205
  # # ^^^^ BOOM! database error!
201
206
  # end
202
207
  #
203
208
  # Note that "TRUNCATE" is also a MySQL DDL statement!
204
209
  module ClassMethods
205
- # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
210
+ # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
206
211
  def transaction(options = {}, &block)
207
- # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
208
212
  connection.transaction(options, &block)
209
213
  end
210
214
 
215
+ def before_commit(*args, &block) # :nodoc:
216
+ set_options_for_callbacks!(args)
217
+ set_callback(:before_commit, :before, *args, &block)
218
+ end
219
+
220
+ # This callback is called after a record has been created, updated, or destroyed.
221
+ #
222
+ # You can specify that the callback should only be fired by a certain action with
223
+ # the +:on+ option:
224
+ #
225
+ # after_commit :do_foo, on: :create
226
+ # after_commit :do_bar, on: :update
227
+ # after_commit :do_baz, on: :destroy
228
+ #
229
+ # after_commit :do_foo_bar, on: [:create, :update]
230
+ # after_commit :do_bar_baz, on: [:update, :destroy]
231
+ #
211
232
  def after_commit(*args, &block)
212
- options = args.last
213
- if options.is_a?(Hash) && options[:on]
214
- options[:if] = Array.wrap(options[:if])
215
- options[:if] << "transaction_include_action?(:#{options[:on]})"
216
- end
233
+ set_options_for_callbacks!(args)
234
+ set_callback(:commit, :after, *args, &block)
235
+ end
236
+
237
+ # Shortcut for <tt>after_commit :hook, on: [ :create, :update ]</tt>.
238
+ def after_save_commit(*args, &block)
239
+ set_options_for_callbacks!(args, on: [ :create, :update ])
240
+ set_callback(:commit, :after, *args, &block)
241
+ end
242
+
243
+ # Shortcut for <tt>after_commit :hook, on: :create</tt>.
244
+ def after_create_commit(*args, &block)
245
+ set_options_for_callbacks!(args, on: :create)
246
+ set_callback(:commit, :after, *args, &block)
247
+ end
248
+
249
+ # Shortcut for <tt>after_commit :hook, on: :update</tt>.
250
+ def after_update_commit(*args, &block)
251
+ set_options_for_callbacks!(args, on: :update)
217
252
  set_callback(:commit, :after, *args, &block)
218
253
  end
219
254
 
255
+ # Shortcut for <tt>after_commit :hook, on: :destroy</tt>.
256
+ def after_destroy_commit(*args, &block)
257
+ set_options_for_callbacks!(args, on: :destroy)
258
+ set_callback(:commit, :after, *args, &block)
259
+ end
260
+
261
+ # This callback is called after a create, update, or destroy are rolled back.
262
+ #
263
+ # Please check the documentation of #after_commit for options.
220
264
  def after_rollback(*args, &block)
221
- options = args.last
222
- if options.is_a?(Hash) && options[:on]
223
- options[:if] = Array.wrap(options[:if])
224
- options[:if] << "transaction_include_action?(:#{options[:on]})"
225
- end
265
+ set_options_for_callbacks!(args)
226
266
  set_callback(:rollback, :after, *args, &block)
227
267
  end
268
+
269
+ def before_commit_without_transaction_enrollment(*args, &block) # :nodoc:
270
+ set_options_for_callbacks!(args)
271
+ set_callback(:before_commit_without_transaction_enrollment, :before, *args, &block)
272
+ end
273
+
274
+ def after_commit_without_transaction_enrollment(*args, &block) # :nodoc:
275
+ set_options_for_callbacks!(args)
276
+ set_callback(:commit_without_transaction_enrollment, :after, *args, &block)
277
+ end
278
+
279
+ def after_rollback_without_transaction_enrollment(*args, &block) # :nodoc:
280
+ set_options_for_callbacks!(args)
281
+ set_callback(:rollback_without_transaction_enrollment, :after, *args, &block)
282
+ end
283
+
284
+ private
285
+
286
+ def set_options_for_callbacks!(args, enforced_options = {})
287
+ options = args.extract_options!.merge!(enforced_options)
288
+ args << options
289
+
290
+ if options[:on]
291
+ fire_on = Array(options[:on])
292
+ assert_valid_transaction_action(fire_on)
293
+ options[:if] = Array(options[:if])
294
+ options[:if].unshift(-> { transaction_include_any_action?(fire_on) })
295
+ end
296
+ end
297
+
298
+ def assert_valid_transaction_action(actions)
299
+ if (actions - ACTIONS).any?
300
+ raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
301
+ end
302
+ end
228
303
  end
229
304
 
230
305
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
@@ -237,49 +312,47 @@ module ActiveRecord
237
312
  end
238
313
 
239
314
  def save(*) #:nodoc:
240
- rollback_active_record_state! do
241
- with_transaction_returning_status { super }
242
- end
315
+ with_transaction_returning_status { super }
243
316
  end
244
317
 
245
318
  def save!(*) #:nodoc:
246
319
  with_transaction_returning_status { super }
247
320
  end
248
321
 
249
- # Reset id and @new_record if the transaction rolls back.
250
- def rollback_active_record_state!
251
- remember_transaction_record_state
252
- yield
253
- rescue Exception
254
- IdentityMap.remove(self) if IdentityMap.enabled?
255
- restore_transaction_record_state
256
- raise
257
- ensure
258
- clear_transaction_record_state
322
+ def touch(*) #:nodoc:
323
+ with_transaction_returning_status { super }
259
324
  end
260
325
 
261
- # Call the after_commit callbacks
262
- def committed! #:nodoc:
263
- run_callbacks :commit
264
- ensure
265
- clear_transaction_record_state
326
+ def before_committed! # :nodoc:
327
+ _run_before_commit_without_transaction_enrollment_callbacks
328
+ _run_before_commit_callbacks
266
329
  end
267
330
 
268
- # Call the after rollback callbacks. The restore_state argument indicates if the record
269
- # state should be rolled back to the beginning or just to the last savepoint.
270
- def rolledback!(force_restore_state = false) #:nodoc:
271
- run_callbacks :rollback
331
+ # Call the #after_commit callbacks.
332
+ #
333
+ # Ensure that it is not called if the object was never persisted (failed create),
334
+ # but call it after the commit of a destroyed object.
335
+ def committed!(should_run_callbacks: true) #:nodoc:
336
+ if should_run_callbacks
337
+ @_committed_already_called = true
338
+ _run_commit_without_transaction_enrollment_callbacks
339
+ _run_commit_callbacks
340
+ end
272
341
  ensure
273
- IdentityMap.remove(self) if IdentityMap.enabled?
274
- restore_transaction_record_state(force_restore_state)
342
+ @_committed_already_called = false
343
+ force_clear_transaction_record_state
275
344
  end
276
345
 
277
- # Add the record to the current transaction so that the :after_rollback and :after_commit callbacks
278
- # can be called.
279
- def add_to_transaction
280
- if self.class.connection.add_transaction_record(self)
281
- remember_transaction_record_state
346
+ # Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
347
+ # state should be rolled back to the beginning or just to the last savepoint.
348
+ def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
349
+ if should_run_callbacks
350
+ _run_rollback_callbacks
351
+ _run_rollback_without_transaction_enrollment_callbacks
282
352
  end
353
+ ensure
354
+ restore_transaction_record_state(force_restore_state)
355
+ clear_transaction_record_state
283
356
  end
284
357
 
285
358
  # Executes +method+ within a transaction and captures its return value as a
@@ -291,72 +364,130 @@ module ActiveRecord
291
364
  def with_transaction_returning_status
292
365
  status = nil
293
366
  self.class.transaction do
294
- add_to_transaction
367
+ if has_transactional_callbacks?
368
+ add_to_transaction
369
+ else
370
+ sync_with_transaction_state if @transaction_state&.finalized?
371
+ @transaction_state = self.class.connection.transaction_state
372
+ end
373
+ remember_transaction_record_state
374
+
295
375
  status = yield
296
376
  raise ActiveRecord::Rollback unless status
297
377
  end
298
378
  status
299
379
  end
300
380
 
301
- protected
381
+ def trigger_transactional_callbacks? # :nodoc:
382
+ (@_new_record_before_last_commit || _trigger_update_callback) && persisted? ||
383
+ _trigger_destroy_callback && destroyed?
384
+ end
385
+
386
+ private
387
+ attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
302
388
 
303
- # Save the new record state and id of a record so it can be restored later if a transaction fails.
304
- def remember_transaction_record_state #:nodoc:
305
- @_start_transaction_state ||= {}
306
- @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
307
- unless @_start_transaction_state.include?(:new_record)
308
- @_start_transaction_state[:new_record] = @new_record
389
+ # Save the new record state and id of a record so it can be restored later if a transaction fails.
390
+ def remember_transaction_record_state
391
+ @_start_transaction_state ||= {
392
+ id: id,
393
+ new_record: @new_record,
394
+ destroyed: @destroyed,
395
+ attributes: @attributes,
396
+ frozen?: frozen?,
397
+ level: 0
398
+ }
399
+ @_start_transaction_state[:level] += 1
400
+
401
+ if _committed_already_called
402
+ @_new_record_before_last_commit = false
403
+ else
404
+ @_new_record_before_last_commit = @_start_transaction_state[:new_record]
405
+ end
309
406
  end
310
- unless @_start_transaction_state.include?(:destroyed)
311
- @_start_transaction_state[:destroyed] = @destroyed
407
+
408
+ # Clear the new record state and id of a record.
409
+ def clear_transaction_record_state
410
+ return unless @_start_transaction_state
411
+ @_start_transaction_state[:level] -= 1
412
+ force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
312
413
  end
313
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
314
- end
315
414
 
316
- # Clear the new record state and id of a record.
317
- def clear_transaction_record_state #:nodoc:
318
- if defined?(@_start_transaction_state)
319
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
320
- remove_instance_variable(:@_start_transaction_state) if @_start_transaction_state[:level] < 1
415
+ # Force to clear the transaction record state.
416
+ def force_clear_transaction_record_state
417
+ @_start_transaction_state = nil
418
+ @transaction_state = nil
321
419
  end
322
- end
323
420
 
324
- # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
325
- def restore_transaction_record_state(force = false) #:nodoc:
326
- if defined?(@_start_transaction_state)
327
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
328
- if @_start_transaction_state[:level] < 1
329
- restore_state = remove_instance_variable(:@_start_transaction_state)
330
- was_frozen = @attributes.frozen?
331
- @attributes = @attributes.dup if was_frozen
332
- @new_record = restore_state[:new_record]
333
- @destroyed = restore_state[:destroyed]
334
- if restore_state.has_key?(:id)
335
- self.id = restore_state[:id]
336
- else
337
- @attributes.delete(self.class.primary_key)
338
- @attributes_cache.delete(self.class.primary_key)
421
+ # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
422
+ def restore_transaction_record_state(force_restore_state = false)
423
+ if restore_state = @_start_transaction_state
424
+ if force_restore_state || restore_state[:level] <= 1
425
+ @new_record = restore_state[:new_record]
426
+ @destroyed = restore_state[:destroyed]
427
+ @attributes = restore_state[:attributes].map do |attr|
428
+ value = @attributes.fetch_value(attr.name)
429
+ attr = attr.with_value_from_user(value) if attr.value != value
430
+ attr
431
+ end
432
+ @mutations_from_database = nil
433
+ @mutations_before_last_save = nil
434
+ if @attributes.fetch_value(@primary_key) != restore_state[:id]
435
+ @attributes.write_from_user(@primary_key, restore_state[:id])
436
+ end
437
+ freeze if restore_state[:frozen?]
339
438
  end
340
- @attributes.freeze if was_frozen
341
439
  end
342
440
  end
343
- end
344
441
 
345
- # Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
346
- def transaction_record_state(state) #:nodoc:
347
- @_start_transaction_state[state] if defined?(@_start_transaction_state)
348
- end
442
+ # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
443
+ def transaction_include_any_action?(actions)
444
+ actions.any? do |action|
445
+ case action
446
+ when :create
447
+ persisted? && @_new_record_before_last_commit
448
+ when :update
449
+ !(@_new_record_before_last_commit || destroyed?) && _trigger_update_callback
450
+ when :destroy
451
+ _trigger_destroy_callback
452
+ end
453
+ end
454
+ end
349
455
 
350
- # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
351
- def transaction_include_action?(action) #:nodoc:
352
- case action
353
- when :create
354
- transaction_record_state(:new_record)
355
- when :destroy
356
- destroyed?
357
- when :update
358
- !(transaction_record_state(:new_record) || destroyed?)
456
+ # Add the record to the current transaction so that the #after_rollback and #after_commit
457
+ # callbacks can be called.
458
+ def add_to_transaction
459
+ self.class.connection.add_transaction_record(self)
460
+ end
461
+
462
+ def has_transactional_callbacks?
463
+ !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
464
+ end
465
+
466
+ # Updates the attributes on this particular Active Record object so that
467
+ # if it's associated with a transaction, then the state of the Active Record
468
+ # object will be updated to reflect the current state of the transaction.
469
+ #
470
+ # The <tt>@transaction_state</tt> variable stores the states of the associated
471
+ # transaction. This relies on the fact that a transaction can only be in
472
+ # one rollback or commit (otherwise a list of states would be required).
473
+ # Each Active Record object inside of a transaction carries that transaction's
474
+ # TransactionState.
475
+ #
476
+ # This method checks to see if the ActiveRecord object's state reflects
477
+ # the TransactionState, and rolls back or commits the Active Record object
478
+ # as appropriate.
479
+ def sync_with_transaction_state
480
+ if transaction_state = @transaction_state
481
+ if transaction_state.fully_committed?
482
+ force_clear_transaction_record_state
483
+ elsif transaction_state.committed?
484
+ clear_transaction_record_state
485
+ elsif transaction_state.rolledback?
486
+ force_restore_state = transaction_state.fully_rolledback?
487
+ restore_transaction_record_state(force_restore_state)
488
+ clear_transaction_record_state
489
+ end
490
+ end
359
491
  end
360
- end
361
492
  end
362
493
  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