activerecord 5.2.6 → 6.1.3.2

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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1038 -571
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +13 -12
  7. data/lib/active_record/aggregations.rb +9 -8
  8. data/lib/active_record/association_relation.rb +30 -10
  9. data/lib/active_record/associations.rb +137 -25
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +95 -42
  12. data/lib/active_record/associations/association_scope.rb +23 -21
  13. data/lib/active_record/associations/belongs_to_association.rb +54 -46
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  15. data/lib/active_record/associations/builder/association.rb +45 -22
  16. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  17. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  19. data/lib/active_record/associations/builder/has_many.rb +8 -2
  20. data/lib/active_record/associations/builder/has_one.rb +33 -2
  21. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  22. data/lib/active_record/associations/collection_association.rb +31 -29
  23. data/lib/active_record/associations/collection_proxy.rb +25 -21
  24. data/lib/active_record/associations/foreign_association.rb +20 -0
  25. data/lib/active_record/associations/has_many_association.rb +26 -13
  26. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  27. data/lib/active_record/associations/has_one_association.rb +43 -31
  28. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  31. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/preloader/association.rb +71 -43
  34. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  35. data/lib/active_record/associations/singular_association.rb +3 -17
  36. data/lib/active_record/associations/through_association.rb +1 -1
  37. data/lib/active_record/attribute_assignment.rb +17 -19
  38. data/lib/active_record/attribute_methods.rb +81 -143
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  42. data/lib/active_record/attribute_methods/query.rb +4 -8
  43. data/lib/active_record/attribute_methods/read.rb +14 -56
  44. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  46. data/lib/active_record/attribute_methods/write.rb +18 -34
  47. data/lib/active_record/attributes.rb +46 -9
  48. data/lib/active_record/autosave_association.rb +57 -42
  49. data/lib/active_record/base.rb +4 -17
  50. data/lib/active_record/callbacks.rb +158 -43
  51. data/lib/active_record/coders/yaml_column.rb +1 -2
  52. data/lib/active_record/connection_adapters.rb +50 -0
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  58. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  60. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -90
  61. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  63. data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
  64. data/lib/active_record/connection_adapters/abstract_adapter.rb +228 -98
  65. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  66. data/lib/active_record/connection_adapters/column.rb +30 -12
  67. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  68. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  69. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
  71. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  77. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  79. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  80. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
  83. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  99. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  101. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  102. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  103. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  104. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  105. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  106. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  107. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  108. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
  109. data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
  110. data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
  111. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  112. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  113. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  114. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  116. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  117. data/lib/active_record/connection_handling.rb +293 -33
  118. data/lib/active_record/core.rb +323 -97
  119. data/lib/active_record/counter_cache.rb +8 -30
  120. data/lib/active_record/database_configurations.rb +272 -0
  121. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  122. data/lib/active_record/database_configurations/database_config.rb +80 -0
  123. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  124. data/lib/active_record/database_configurations/url_config.rb +53 -0
  125. data/lib/active_record/delegated_type.rb +209 -0
  126. data/lib/active_record/destroy_association_async_job.rb +36 -0
  127. data/lib/active_record/dynamic_matchers.rb +3 -4
  128. data/lib/active_record/enum.rb +111 -37
  129. data/lib/active_record/errors.rb +62 -19
  130. data/lib/active_record/explain.rb +10 -6
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +10 -17
  133. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  134. data/lib/active_record/fixture_set/render_context.rb +17 -0
  135. data/lib/active_record/fixture_set/table_row.rb +152 -0
  136. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  137. data/lib/active_record/fixtures.rb +200 -481
  138. data/lib/active_record/gem_version.rb +4 -4
  139. data/lib/active_record/inheritance.rb +53 -24
  140. data/lib/active_record/insert_all.rb +208 -0
  141. data/lib/active_record/integration.rb +67 -17
  142. data/lib/active_record/internal_metadata.rb +26 -9
  143. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  144. data/lib/active_record/locking/optimistic.rb +37 -23
  145. data/lib/active_record/locking/pessimistic.rb +9 -5
  146. data/lib/active_record/log_subscriber.rb +35 -35
  147. data/lib/active_record/middleware/database_selector.rb +77 -0
  148. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  149. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  150. data/lib/active_record/migration.rb +206 -157
  151. data/lib/active_record/migration/command_recorder.rb +96 -44
  152. data/lib/active_record/migration/compatibility.rb +142 -64
  153. data/lib/active_record/migration/join_table.rb +0 -1
  154. data/lib/active_record/model_schema.rb +148 -22
  155. data/lib/active_record/nested_attributes.rb +4 -7
  156. data/lib/active_record/no_touching.rb +8 -1
  157. data/lib/active_record/null_relation.rb +0 -1
  158. data/lib/active_record/persistence.rb +267 -59
  159. data/lib/active_record/query_cache.rb +21 -4
  160. data/lib/active_record/querying.rb +40 -23
  161. data/lib/active_record/railtie.rb +115 -58
  162. data/lib/active_record/railties/console_sandbox.rb +2 -4
  163. data/lib/active_record/railties/controller_runtime.rb +30 -35
  164. data/lib/active_record/railties/databases.rake +408 -78
  165. data/lib/active_record/readonly_attributes.rb +4 -0
  166. data/lib/active_record/reflection.rb +109 -93
  167. data/lib/active_record/relation.rb +374 -104
  168. data/lib/active_record/relation/batches.rb +44 -35
  169. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  170. data/lib/active_record/relation/calculations.rb +153 -90
  171. data/lib/active_record/relation/delegation.rb +35 -50
  172. data/lib/active_record/relation/finder_methods.rb +64 -39
  173. data/lib/active_record/relation/from_clause.rb +5 -1
  174. data/lib/active_record/relation/merger.rb +32 -40
  175. data/lib/active_record/relation/predicate_builder.rb +62 -45
  176. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  177. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  179. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  180. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  181. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  182. data/lib/active_record/relation/query_attribute.rb +13 -8
  183. data/lib/active_record/relation/query_methods.rb +475 -186
  184. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  185. data/lib/active_record/relation/spawn_methods.rb +9 -9
  186. data/lib/active_record/relation/where_clause.rb +111 -61
  187. data/lib/active_record/result.rb +64 -38
  188. data/lib/active_record/runtime_registry.rb +2 -2
  189. data/lib/active_record/sanitization.rb +22 -41
  190. data/lib/active_record/schema.rb +2 -11
  191. data/lib/active_record/schema_dumper.rb +54 -9
  192. data/lib/active_record/schema_migration.rb +7 -9
  193. data/lib/active_record/scoping.rb +8 -9
  194. data/lib/active_record/scoping/default.rb +4 -6
  195. data/lib/active_record/scoping/named.rb +17 -24
  196. data/lib/active_record/secure_token.rb +16 -8
  197. data/lib/active_record/serialization.rb +5 -3
  198. data/lib/active_record/signed_id.rb +116 -0
  199. data/lib/active_record/statement_cache.rb +49 -6
  200. data/lib/active_record/store.rb +88 -9
  201. data/lib/active_record/suppressor.rb +2 -2
  202. data/lib/active_record/table_metadata.rb +42 -43
  203. data/lib/active_record/tasks/database_tasks.rb +277 -81
  204. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  205. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  206. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  207. data/lib/active_record/test_databases.rb +24 -0
  208. data/lib/active_record/test_fixtures.rb +246 -0
  209. data/lib/active_record/timestamp.rb +43 -32
  210. data/lib/active_record/touch_later.rb +23 -22
  211. data/lib/active_record/transactions.rb +62 -118
  212. data/lib/active_record/translation.rb +1 -1
  213. data/lib/active_record/type.rb +10 -5
  214. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  215. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  216. data/lib/active_record/type/serialized.rb +6 -3
  217. data/lib/active_record/type/time.rb +10 -0
  218. data/lib/active_record/type/type_map.rb +0 -1
  219. data/lib/active_record/type/unsigned_integer.rb +0 -1
  220. data/lib/active_record/type_caster/connection.rb +15 -15
  221. data/lib/active_record/type_caster/map.rb +8 -8
  222. data/lib/active_record/validations.rb +4 -3
  223. data/lib/active_record/validations/associated.rb +1 -2
  224. data/lib/active_record/validations/numericality.rb +35 -0
  225. data/lib/active_record/validations/uniqueness.rb +38 -30
  226. data/lib/arel.rb +54 -0
  227. data/lib/arel/alias_predication.rb +9 -0
  228. data/lib/arel/attributes/attribute.rb +41 -0
  229. data/lib/arel/collectors/bind.rb +29 -0
  230. data/lib/arel/collectors/composite.rb +39 -0
  231. data/lib/arel/collectors/plain_string.rb +20 -0
  232. data/lib/arel/collectors/sql_string.rb +27 -0
  233. data/lib/arel/collectors/substitute_binds.rb +35 -0
  234. data/lib/arel/crud.rb +42 -0
  235. data/lib/arel/delete_manager.rb +18 -0
  236. data/lib/arel/errors.rb +9 -0
  237. data/lib/arel/expressions.rb +29 -0
  238. data/lib/arel/factory_methods.rb +49 -0
  239. data/lib/arel/insert_manager.rb +49 -0
  240. data/lib/arel/math.rb +45 -0
  241. data/lib/arel/nodes.rb +70 -0
  242. data/lib/arel/nodes/and.rb +32 -0
  243. data/lib/arel/nodes/ascending.rb +23 -0
  244. data/lib/arel/nodes/binary.rb +126 -0
  245. data/lib/arel/nodes/bind_param.rb +44 -0
  246. data/lib/arel/nodes/case.rb +55 -0
  247. data/lib/arel/nodes/casted.rb +62 -0
  248. data/lib/arel/nodes/comment.rb +29 -0
  249. data/lib/arel/nodes/count.rb +12 -0
  250. data/lib/arel/nodes/delete_statement.rb +45 -0
  251. data/lib/arel/nodes/descending.rb +23 -0
  252. data/lib/arel/nodes/equality.rb +15 -0
  253. data/lib/arel/nodes/extract.rb +24 -0
  254. data/lib/arel/nodes/false.rb +16 -0
  255. data/lib/arel/nodes/full_outer_join.rb +8 -0
  256. data/lib/arel/nodes/function.rb +44 -0
  257. data/lib/arel/nodes/grouping.rb +11 -0
  258. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  259. data/lib/arel/nodes/in.rb +15 -0
  260. data/lib/arel/nodes/infix_operation.rb +92 -0
  261. data/lib/arel/nodes/inner_join.rb +8 -0
  262. data/lib/arel/nodes/insert_statement.rb +37 -0
  263. data/lib/arel/nodes/join_source.rb +20 -0
  264. data/lib/arel/nodes/matches.rb +18 -0
  265. data/lib/arel/nodes/named_function.rb +23 -0
  266. data/lib/arel/nodes/node.rb +51 -0
  267. data/lib/arel/nodes/node_expression.rb +13 -0
  268. data/lib/arel/nodes/ordering.rb +27 -0
  269. data/lib/arel/nodes/outer_join.rb +8 -0
  270. data/lib/arel/nodes/over.rb +15 -0
  271. data/lib/arel/nodes/regexp.rb +16 -0
  272. data/lib/arel/nodes/right_outer_join.rb +8 -0
  273. data/lib/arel/nodes/select_core.rb +67 -0
  274. data/lib/arel/nodes/select_statement.rb +41 -0
  275. data/lib/arel/nodes/sql_literal.rb +19 -0
  276. data/lib/arel/nodes/string_join.rb +11 -0
  277. data/lib/arel/nodes/table_alias.rb +31 -0
  278. data/lib/arel/nodes/terminal.rb +16 -0
  279. data/lib/arel/nodes/true.rb +16 -0
  280. data/lib/arel/nodes/unary.rb +44 -0
  281. data/lib/arel/nodes/unary_operation.rb +20 -0
  282. data/lib/arel/nodes/unqualified_column.rb +22 -0
  283. data/lib/arel/nodes/update_statement.rb +41 -0
  284. data/lib/arel/nodes/values_list.rb +9 -0
  285. data/lib/arel/nodes/window.rb +126 -0
  286. data/lib/arel/nodes/with.rb +11 -0
  287. data/lib/arel/order_predications.rb +13 -0
  288. data/lib/arel/predications.rb +250 -0
  289. data/lib/arel/select_manager.rb +270 -0
  290. data/lib/arel/table.rb +118 -0
  291. data/lib/arel/tree_manager.rb +72 -0
  292. data/lib/arel/update_manager.rb +34 -0
  293. data/lib/arel/visitors.rb +13 -0
  294. data/lib/arel/visitors/dot.rb +308 -0
  295. data/lib/arel/visitors/mysql.rb +93 -0
  296. data/lib/arel/visitors/postgresql.rb +120 -0
  297. data/lib/arel/visitors/sqlite.rb +38 -0
  298. data/lib/arel/visitors/to_sql.rb +899 -0
  299. data/lib/arel/visitors/visitor.rb +45 -0
  300. data/lib/arel/window_predications.rb +9 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration.rb +19 -2
  303. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  304. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  305. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +119 -34
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -56,54 +56,60 @@ module ActiveRecord
56
56
  def touch_attributes_with_time(*names, time: nil)
57
57
  attribute_names = timestamp_attributes_for_update_in_model
58
58
  attribute_names |= names.map(&:to_s)
59
- time ||= current_time_from_proper_timezone
60
- attribute_names.each_with_object({}) { |attr_name, result| result[attr_name] = time }
59
+ attribute_names.index_with(time || current_time_from_proper_timezone)
61
60
  end
62
61
 
63
- private
64
- def timestamp_attributes_for_create_in_model
65
- timestamp_attributes_for_create.select { |c| column_names.include?(c) }
66
- end
62
+ def timestamp_attributes_for_create_in_model
63
+ @timestamp_attributes_for_create_in_model ||=
64
+ (timestamp_attributes_for_create & column_names).freeze
65
+ end
67
66
 
68
- def timestamp_attributes_for_update_in_model
69
- timestamp_attributes_for_update.select { |c| column_names.include?(c) }
70
- end
67
+ def timestamp_attributes_for_update_in_model
68
+ @timestamp_attributes_for_update_in_model ||=
69
+ (timestamp_attributes_for_update & column_names).freeze
70
+ end
71
71
 
72
- def all_timestamp_attributes_in_model
73
- timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model
74
- end
72
+ def all_timestamp_attributes_in_model
73
+ @all_timestamp_attributes_in_model ||=
74
+ (timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model).freeze
75
+ end
76
+
77
+ def current_time_from_proper_timezone
78
+ default_timezone == :utc ? Time.now.utc : Time.now
79
+ end
75
80
 
81
+ private
76
82
  def timestamp_attributes_for_create
77
- ["created_at", "created_on"]
83
+ ["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
78
84
  end
79
85
 
80
86
  def timestamp_attributes_for_update
81
- ["updated_at", "updated_on"]
87
+ ["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
82
88
  end
83
89
 
84
- def current_time_from_proper_timezone
85
- default_timezone == :utc ? Time.now.utc : Time.now
90
+ def reload_schema_from_cache
91
+ @timestamp_attributes_for_create_in_model = nil
92
+ @timestamp_attributes_for_update_in_model = nil
93
+ @all_timestamp_attributes_in_model = nil
94
+ super
86
95
  end
87
96
  end
88
97
 
89
98
  private
90
-
91
99
  def _create_record
92
100
  if record_timestamps
93
101
  current_time = current_time_from_proper_timezone
94
102
 
95
103
  all_timestamp_attributes_in_model.each do |column|
96
- if !attribute_present?(column)
97
- _write_attribute(column, current_time)
98
- end
104
+ _write_attribute(column, current_time) unless _read_attribute(column)
99
105
  end
100
106
  end
101
107
 
102
108
  super
103
109
  end
104
110
 
105
- def _update_record(*args, touch: true, **options)
106
- if touch && should_record_timestamps?
111
+ def _update_record
112
+ if @_touch_record && should_record_timestamps?
107
113
  current_time = current_time_from_proper_timezone
108
114
 
109
115
  timestamp_attributes_for_update_in_model.each do |column|
@@ -111,7 +117,13 @@ module ActiveRecord
111
117
  _write_attribute(column, current_time)
112
118
  end
113
119
  end
114
- super(*args)
120
+
121
+ super
122
+ end
123
+
124
+ def create_or_update(touch: true, **)
125
+ @_touch_record = touch
126
+ super
115
127
  end
116
128
 
117
129
  def should_record_timestamps?
@@ -119,26 +131,25 @@ module ActiveRecord
119
131
  end
120
132
 
121
133
  def timestamp_attributes_for_create_in_model
122
- self.class.send(:timestamp_attributes_for_create_in_model)
134
+ self.class.timestamp_attributes_for_create_in_model
123
135
  end
124
136
 
125
137
  def timestamp_attributes_for_update_in_model
126
- self.class.send(:timestamp_attributes_for_update_in_model)
138
+ self.class.timestamp_attributes_for_update_in_model
127
139
  end
128
140
 
129
141
  def all_timestamp_attributes_in_model
130
- self.class.send(:all_timestamp_attributes_in_model)
142
+ self.class.all_timestamp_attributes_in_model
131
143
  end
132
144
 
133
145
  def current_time_from_proper_timezone
134
- self.class.send(:current_time_from_proper_timezone)
146
+ self.class.current_time_from_proper_timezone
135
147
  end
136
148
 
137
- def max_updated_column_timestamp(timestamp_names = timestamp_attributes_for_update_in_model)
138
- timestamp_names
139
- .map { |attr| self[attr] }
149
+ def max_updated_column_timestamp
150
+ timestamp_attributes_for_update_in_model
151
+ .map { |attr| self[attr]&.to_time }
140
152
  .compact
141
- .map(&:to_time)
142
153
  .max
143
154
  end
144
155
 
@@ -146,7 +157,7 @@ module ActiveRecord
146
157
  def clear_timestamp_attributes
147
158
  all_timestamp_attributes_in_model.each do |attribute_name|
148
159
  self[attribute_name] = nil
149
- clear_attribute_changes([attribute_name])
160
+ clear_attribute_change(attribute_name)
150
161
  end
151
162
  end
152
163
  end
@@ -2,27 +2,26 @@
2
2
 
3
3
  module ActiveRecord
4
4
  # = Active Record Touch Later
5
- module TouchLater
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- before_commit_without_transaction_enrollment :touch_deferred_attributes
5
+ module TouchLater # :nodoc:
6
+ def before_committed!
7
+ touch_deferred_attributes if has_defer_touch_attrs? && persisted?
8
+ super
10
9
  end
11
10
 
12
11
  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
12
+ _raise_record_not_touched_error unless persisted?
19
13
 
20
14
  @_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
21
- @_defer_touch_attrs |= names
15
+ @_defer_touch_attrs |= names.map! do |name|
16
+ name = name.to_s
17
+ self.class.attribute_aliases[name] || name
18
+ end unless names.empty?
19
+
22
20
  @_touch_time = current_time_from_proper_timezone
23
21
 
24
22
  surreptitiously_touch @_defer_touch_attrs
25
- self.class.connection.add_transaction_record self
23
+ add_to_transaction
24
+ @_new_record_before_last_commit ||= false
26
25
 
27
26
  # touch the parents as we are not calling the after_save callbacks
28
27
  self.class.reflect_on_all_associations(:belongs_to).each do |r|
@@ -35,22 +34,24 @@ module ActiveRecord
35
34
  def touch(*names, time: nil) # :nodoc:
36
35
  if has_defer_touch_attrs?
37
36
  names |= @_defer_touch_attrs
37
+ super(*names, time: time)
38
+ @_defer_touch_attrs, @_touch_time = nil, nil
39
+ else
40
+ super
38
41
  end
39
- super(*names, time: time)
40
42
  end
41
43
 
42
44
  private
43
-
44
- def surreptitiously_touch(attrs)
45
- attrs.each { |attr| write_attribute attr, @_touch_time }
46
- clear_attribute_changes attrs
45
+ def surreptitiously_touch(attr_names)
46
+ attr_names.each do |attr_name|
47
+ _write_attribute(attr_name, @_touch_time)
48
+ clear_attribute_change(attr_name)
49
+ end
47
50
  end
48
51
 
49
52
  def touch_deferred_attributes
50
- if has_defer_touch_attrs? && persisted?
51
- touch(*@_defer_touch_attrs, time: @_touch_time)
52
- @_defer_touch_attrs, @_touch_time = nil, nil
53
- end
53
+ @_skip_dirty_tracking = true
54
+ touch(time: @_touch_time)
54
55
  end
55
56
 
56
57
  def has_defer_touch_attrs?
@@ -10,9 +10,6 @@ module ActiveRecord
10
10
  included do
11
11
  define_callbacks :commit, :rollback,
12
12
  :before_commit,
13
- :before_commit_without_transaction_enrollment,
14
- :commit_without_transaction_enrollment,
15
- :rollback_without_transaction_enrollment,
16
13
  scope: [:kind, :name]
17
14
  end
18
15
 
@@ -164,13 +161,13 @@ module ActiveRecord
164
161
  # end
165
162
  # end
166
163
  #
167
- # only "Kotori" is created. This works on MySQL and PostgreSQL. SQLite3 version >= '3.6.8' also supports it.
164
+ # only "Kotori" is created.
168
165
  #
169
166
  # Most databases don't support true nested transactions. At the time of
170
167
  # writing, the only database that we're aware of that supports true nested
171
168
  # transactions, is MS-SQL. Because of this, Active Record emulates nested
172
- # transactions by using savepoints on MySQL and PostgreSQL. See
173
- # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
169
+ # transactions by using savepoints. See
170
+ # https://dev.mysql.com/doc/refman/en/savepoint.html
174
171
  # for more information about savepoints.
175
172
  #
176
173
  # === \Callbacks
@@ -208,8 +205,8 @@ module ActiveRecord
208
205
  # Note that "TRUNCATE" is also a MySQL DDL statement!
209
206
  module ClassMethods
210
207
  # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
211
- def transaction(options = {}, &block)
212
- connection.transaction(options, &block)
208
+ def transaction(**options, &block)
209
+ connection.transaction(**options, &block)
213
210
  end
214
211
 
215
212
  def before_commit(*args, &block) # :nodoc:
@@ -234,6 +231,12 @@ module ActiveRecord
234
231
  set_callback(:commit, :after, *args, &block)
235
232
  end
236
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
+
237
240
  # Shortcut for <tt>after_commit :hook, on: :create</tt>.
238
241
  def after_create_commit(*args, &block)
239
242
  set_options_for_callbacks!(args, on: :create)
@@ -260,23 +263,7 @@ module ActiveRecord
260
263
  set_callback(:rollback, :after, *args, &block)
261
264
  end
262
265
 
263
- def before_commit_without_transaction_enrollment(*args, &block) # :nodoc:
264
- set_options_for_callbacks!(args)
265
- set_callback(:before_commit_without_transaction_enrollment, :before, *args, &block)
266
- end
267
-
268
- def after_commit_without_transaction_enrollment(*args, &block) # :nodoc:
269
- set_options_for_callbacks!(args)
270
- set_callback(:commit_without_transaction_enrollment, :after, *args, &block)
271
- end
272
-
273
- def after_rollback_without_transaction_enrollment(*args, &block) # :nodoc:
274
- set_options_for_callbacks!(args)
275
- set_callback(:rollback_without_transaction_enrollment, :after, *args, &block)
276
- end
277
-
278
266
  private
279
-
280
267
  def set_options_for_callbacks!(args, enforced_options = {})
281
268
  options = args.extract_options!.merge!(enforced_options)
282
269
  args << options
@@ -284,8 +271,10 @@ module ActiveRecord
284
271
  if options[:on]
285
272
  fire_on = Array(options[:on])
286
273
  assert_valid_transaction_action(fire_on)
287
- options[:if] = Array(options[:if])
288
- options[:if].unshift(-> { transaction_include_any_action?(fire_on) })
274
+ options[:if] = [
275
+ -> { transaction_include_any_action?(fire_on) },
276
+ *options[:if]
277
+ ]
289
278
  end
290
279
  end
291
280
 
@@ -297,41 +286,27 @@ module ActiveRecord
297
286
  end
298
287
 
299
288
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
300
- def transaction(options = {}, &block)
301
- self.class.transaction(options, &block)
289
+ def transaction(**options, &block)
290
+ self.class.transaction(**options, &block)
302
291
  end
303
292
 
304
293
  def destroy #:nodoc:
305
294
  with_transaction_returning_status { super }
306
295
  end
307
296
 
308
- def save(*) #:nodoc:
309
- rollback_active_record_state! do
310
- with_transaction_returning_status { super }
311
- end
312
- end
313
-
314
- def save!(*) #:nodoc:
297
+ def save(**) #:nodoc:
315
298
  with_transaction_returning_status { super }
316
299
  end
317
300
 
318
- def touch(*) #:nodoc:
301
+ def save!(**) #:nodoc:
319
302
  with_transaction_returning_status { super }
320
303
  end
321
304
 
322
- # Reset id and @new_record if the transaction rolls back.
323
- def rollback_active_record_state!
324
- remember_transaction_record_state
325
- yield
326
- rescue Exception
327
- restore_transaction_record_state
328
- raise
329
- ensure
330
- clear_transaction_record_state
305
+ def touch(*, **) #:nodoc:
306
+ with_transaction_returning_status { super }
331
307
  end
332
308
 
333
309
  def before_committed! # :nodoc:
334
- _run_before_commit_without_transaction_enrollment_callbacks
335
310
  _run_before_commit_callbacks
336
311
  end
337
312
 
@@ -341,13 +316,12 @@ module ActiveRecord
341
316
  # but call it after the commit of a destroyed object.
342
317
  def committed!(should_run_callbacks: true) #:nodoc:
343
318
  force_clear_transaction_record_state
344
- if should_run_callbacks && (destroyed? || persisted?)
319
+ if should_run_callbacks
345
320
  @_committed_already_called = true
346
- _run_commit_without_transaction_enrollment_callbacks
347
321
  _run_commit_callbacks
348
322
  end
349
323
  ensure
350
- @_committed_already_called = false
324
+ @_committed_already_called = @_trigger_update_callback = @_trigger_destroy_callback = false
351
325
  end
352
326
 
353
327
  # Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
@@ -355,23 +329,11 @@ module ActiveRecord
355
329
  def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
356
330
  if should_run_callbacks
357
331
  _run_rollback_callbacks
358
- _run_rollback_without_transaction_enrollment_callbacks
359
332
  end
360
333
  ensure
361
334
  restore_transaction_record_state(force_restore_state)
362
335
  clear_transaction_record_state
363
- end
364
-
365
- # Add the record to the current transaction so that the #after_rollback and #after_commit callbacks
366
- # can be called.
367
- def add_to_transaction
368
- if has_transactional_callbacks?
369
- self.class.connection.add_transaction_record(self)
370
- else
371
- sync_with_transaction_state
372
- set_transaction_state(self.class.connection.transaction_state)
373
- end
374
- remember_transaction_record_state
336
+ @_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state
375
337
  end
376
338
 
377
339
  # Executes +method+ within a transaction and captures its return value as a
@@ -382,36 +344,40 @@ module ActiveRecord
382
344
  # instance.
383
345
  def with_transaction_returning_status
384
346
  status = nil
385
- self.class.transaction do
386
- add_to_transaction
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
353
+
387
354
  status = yield
388
355
  raise ActiveRecord::Rollback unless status
389
356
  end
390
357
  status
391
- ensure
392
- if @transaction_state && @transaction_state.committed?
393
- clear_transaction_record_state
394
- end
395
358
  end
396
359
 
397
- protected
398
- attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
360
+ def trigger_transactional_callbacks? # :nodoc:
361
+ (@_new_record_before_last_commit || _trigger_update_callback) && persisted? ||
362
+ _trigger_destroy_callback && destroyed?
363
+ end
399
364
 
400
365
  private
366
+ attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
401
367
 
402
368
  # Save the new record state and id of a record so it can be restored later if a transaction fails.
403
369
  def remember_transaction_record_state
404
- @_start_transaction_state.reverse_merge!(
370
+ @_start_transaction_state ||= {
405
371
  id: id,
406
372
  new_record: @new_record,
373
+ previously_new_record: @previously_new_record,
407
374
  destroyed: @destroyed,
375
+ attributes: @attributes,
408
376
  frozen?: frozen?,
409
- )
410
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
411
- remember_new_record_before_last_commit
412
- end
377
+ level: 0
378
+ }
379
+ @_start_transaction_state[:level] += 1
413
380
 
414
- def remember_new_record_before_last_commit
415
381
  if _committed_already_called
416
382
  @_new_record_before_last_commit = false
417
383
  else
@@ -421,27 +387,32 @@ module ActiveRecord
421
387
 
422
388
  # Clear the new record state and id of a record.
423
389
  def clear_transaction_record_state
424
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
390
+ return unless @_start_transaction_state
391
+ @_start_transaction_state[:level] -= 1
425
392
  force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
426
393
  end
427
394
 
428
395
  # Force to clear the transaction record state.
429
396
  def force_clear_transaction_record_state
430
- @_start_transaction_state.clear
397
+ @_start_transaction_state = nil
431
398
  end
432
399
 
433
400
  # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
434
- def restore_transaction_record_state(force = false)
435
- unless @_start_transaction_state.empty?
436
- transaction_level = (@_start_transaction_state[:level] || 0) - 1
437
- if transaction_level < 1 || force
438
- restore_state = @_start_transaction_state
439
- thaw
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
440
404
  @new_record = restore_state[:new_record]
405
+ @previously_new_record = restore_state[:previously_new_record]
441
406
  @destroyed = restore_state[:destroyed]
442
- pk = self.class.primary_key
443
- if pk && _read_attribute(pk) != restore_state[:id]
444
- _write_attribute(pk, restore_state[:id])
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])
445
416
  end
446
417
  freeze if restore_state[:frozen?]
447
418
  end
@@ -462,41 +433,14 @@ module ActiveRecord
462
433
  end
463
434
  end
464
435
 
465
- def set_transaction_state(state)
466
- @transaction_state = state
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)
467
440
  end
468
441
 
469
442
  def has_transactional_callbacks?
470
443
  !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
471
444
  end
472
-
473
- # Updates the attributes on this particular Active Record object so that
474
- # if it's associated with a transaction, then the state of the Active Record
475
- # object will be updated to reflect the current state of the transaction.
476
- #
477
- # The <tt>@transaction_state</tt> variable stores the states of the associated
478
- # transaction. This relies on the fact that a transaction can only be in
479
- # one rollback or commit (otherwise a list of states would be required).
480
- # Each Active Record object inside of a transaction carries that transaction's
481
- # TransactionState.
482
- #
483
- # This method checks to see if the ActiveRecord object's state reflects
484
- # the TransactionState, and rolls back or commits the Active Record object
485
- # as appropriate.
486
- #
487
- # Since Active Record objects can be inside multiple transactions, this
488
- # method recursively goes through the parent of the TransactionState and
489
- # checks if the Active Record object reflects the state of the object.
490
- def sync_with_transaction_state
491
- update_attributes_from_transaction_state(@transaction_state)
492
- end
493
-
494
- def update_attributes_from_transaction_state(transaction_state)
495
- if transaction_state && transaction_state.finalized?
496
- restore_transaction_record_state(transaction_state.fully_rolledback?) if transaction_state.rolledback?
497
- force_clear_transaction_record_state if transaction_state.fully_committed?
498
- clear_transaction_record_state if transaction_state.fully_completed?
499
- end
500
- end
501
445
  end
502
446
  end