activerecord 4.2.0 → 6.1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1221 -796
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +267 -249
  8. data/lib/active_record/association_relation.rb +45 -7
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +172 -67
  11. data/lib/active_record/associations/association_scope.rb +105 -129
  12. data/lib/active_record/associations/belongs_to_association.rb +85 -59
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -33
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +168 -279
  22. data/lib/active_record/associations/collection_proxy.rb +263 -155
  23. data/lib/active_record/associations/foreign_association.rb +33 -0
  24. data/lib/active_record/associations/has_many_association.rb +57 -84
  25. data/lib/active_record/associations/has_many_through_association.rb +70 -82
  26. data/lib/active_record/associations/has_one_association.rb +74 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -73
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +175 -164
  32. data/lib/active_record/associations/preloader/association.rb +107 -112
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +99 -96
  35. data/lib/active_record/associations/singular_association.rb +18 -45
  36. data/lib/active_record/associations/through_association.rb +49 -24
  37. data/lib/active_record/associations.rb +1845 -1597
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -138
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -36
  46. data/lib/active_record/attribute_methods/write.rb +25 -56
  47. data/lib/active_record/attribute_methods.rb +153 -162
  48. data/lib/active_record/attributes.rb +234 -70
  49. data/lib/active_record/autosave_association.rb +157 -69
  50. data/lib/active_record/base.rb +49 -50
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +46 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +271 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +78 -161
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +499 -293
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +595 -382
  119. data/lib/active_record/connection_adapters/schema_cache.rb +191 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -389
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +488 -243
  133. data/lib/active_record/counter_cache.rb +71 -50
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +273 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +212 -94
  143. data/lib/active_record/errors.rb +225 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +11 -6
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +273 -496
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +64 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +52 -0
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +103 -95
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +298 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +685 -309
  170. data/lib/active_record/model_schema.rb +420 -113
  171. data/lib/active_record/nested_attributes.rb +265 -216
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +574 -135
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +175 -54
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +533 -216
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +485 -310
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +326 -244
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +318 -256
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +99 -84
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +139 -96
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -409
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +23 -21
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -342
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -26
  209. data/lib/active_record/scoping/default.rb +96 -82
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +133 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +366 -129
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +291 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +181 -152
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -41
  231. data/lib/active_record/type/date_time.rb +4 -38
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +33 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +65 -48
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +44 -28
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -10
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +175 -65
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  347. data/lib/active_record/attribute.rb +0 -149
  348. data/lib/active_record/attribute_decorators.rb +0 -66
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  351. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -30
  363. data/lib/active_record/type/decimal.rb +0 -40
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -55
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -36
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -101
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  374. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -0,0 +1,291 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/enumerable"
4
+
5
+ module ActiveRecord
6
+ module TestFixtures
7
+ extend ActiveSupport::Concern
8
+
9
+ def before_setup # :nodoc:
10
+ setup_fixtures
11
+ super
12
+ end
13
+
14
+ def after_teardown # :nodoc:
15
+ super
16
+ teardown_fixtures
17
+ end
18
+
19
+ included do
20
+ class_attribute :fixture_path, instance_writer: false
21
+ class_attribute :fixture_table_names, default: []
22
+ class_attribute :fixture_class_names, default: {}
23
+ class_attribute :use_transactional_tests, default: true
24
+ class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
25
+ class_attribute :pre_loaded_fixtures, default: false
26
+ class_attribute :lock_threads, default: true
27
+ end
28
+
29
+ module ClassMethods
30
+ # Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
31
+ #
32
+ # Examples:
33
+ #
34
+ # set_fixture_class some_fixture: SomeModel,
35
+ # 'namespaced/fixture' => Another::Model
36
+ #
37
+ # The keys must be the fixture names, that coincide with the short paths to the fixture files.
38
+ def set_fixture_class(class_names = {})
39
+ self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
40
+ end
41
+
42
+ def fixtures(*fixture_set_names)
43
+ if fixture_set_names.first == :all
44
+ raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
45
+ fixture_set_names = Dir[::File.join(fixture_path, "{**,*}/*.{yml}")].uniq
46
+ fixture_set_names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
47
+ fixture_set_names.map! { |f| f[fixture_path.to_s.size..-5].delete_prefix("/") }
48
+ else
49
+ fixture_set_names = fixture_set_names.flatten.map(&:to_s)
50
+ end
51
+
52
+ self.fixture_table_names |= fixture_set_names
53
+ setup_fixture_accessors(fixture_set_names)
54
+ end
55
+
56
+ def setup_fixture_accessors(fixture_set_names = nil)
57
+ fixture_set_names = Array(fixture_set_names || fixture_table_names)
58
+ methods = Module.new do
59
+ fixture_set_names.each do |fs_name|
60
+ fs_name = fs_name.to_s
61
+ accessor_name = fs_name.tr("/", "_").to_sym
62
+
63
+ define_method(accessor_name) do |*fixture_names|
64
+ force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
65
+ return_single_record = fixture_names.size == 1
66
+ fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
67
+
68
+ @fixture_cache[fs_name] ||= {}
69
+
70
+ instances = fixture_names.map do |f_name|
71
+ f_name = f_name.to_s if f_name.is_a?(Symbol)
72
+ @fixture_cache[fs_name].delete(f_name) if force_reload
73
+
74
+ if @loaded_fixtures[fs_name][f_name]
75
+ @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
76
+ else
77
+ raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
78
+ end
79
+ end
80
+
81
+ return_single_record ? instances.first : instances
82
+ end
83
+ private accessor_name
84
+ end
85
+ end
86
+ include methods
87
+ end
88
+
89
+ def uses_transaction(*methods)
90
+ @uses_transaction = [] unless defined?(@uses_transaction)
91
+ @uses_transaction.concat methods.map(&:to_s)
92
+ end
93
+
94
+ def uses_transaction?(method)
95
+ @uses_transaction = [] unless defined?(@uses_transaction)
96
+ @uses_transaction.include?(method.to_s)
97
+ end
98
+ end
99
+
100
+ def run_in_transaction?
101
+ use_transactional_tests &&
102
+ !self.class.uses_transaction?(name)
103
+ end
104
+
105
+ def setup_fixtures(config = ActiveRecord::Base)
106
+ if pre_loaded_fixtures && !use_transactional_tests
107
+ raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
108
+ end
109
+
110
+ @fixture_cache = {}
111
+ @fixture_connections = []
112
+ @@already_loaded_fixtures ||= {}
113
+ @connection_subscriber = nil
114
+ @legacy_saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
115
+ @saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
116
+
117
+ # Load fixtures once and begin transaction.
118
+ if run_in_transaction?
119
+ if @@already_loaded_fixtures[self.class]
120
+ @loaded_fixtures = @@already_loaded_fixtures[self.class]
121
+ else
122
+ @loaded_fixtures = load_fixtures(config)
123
+ @@already_loaded_fixtures[self.class] = @loaded_fixtures
124
+ end
125
+
126
+ # Begin transactions for connections already established
127
+ @fixture_connections = enlist_fixture_connections
128
+ @fixture_connections.each do |connection|
129
+ connection.begin_transaction joinable: false, _lazy: false
130
+ connection.pool.lock_thread = true if lock_threads
131
+ end
132
+
133
+ # When connections are established in the future, begin a transaction too
134
+ @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
135
+ spec_name = payload[:spec_name] if payload.key?(:spec_name)
136
+ shard = payload[:shard] if payload.key?(:shard)
137
+ setup_shared_connection_pool if ActiveRecord::Base.legacy_connection_handling
138
+
139
+ if spec_name
140
+ begin
141
+ connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
142
+ rescue ConnectionNotEstablished
143
+ connection = nil
144
+ end
145
+
146
+ if connection
147
+ setup_shared_connection_pool unless ActiveRecord::Base.legacy_connection_handling
148
+
149
+ if !@fixture_connections.include?(connection)
150
+ connection.begin_transaction joinable: false, _lazy: false
151
+ connection.pool.lock_thread = true if lock_threads
152
+ @fixture_connections << connection
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ # Load fixtures for every test.
159
+ else
160
+ ActiveRecord::FixtureSet.reset_cache
161
+ @@already_loaded_fixtures[self.class] = nil
162
+ @loaded_fixtures = load_fixtures(config)
163
+ end
164
+
165
+ # Instantiate fixtures for every test if requested.
166
+ instantiate_fixtures if use_instantiated_fixtures
167
+ end
168
+
169
+ def teardown_fixtures
170
+ # Rollback changes if a transaction is active.
171
+ if run_in_transaction?
172
+ ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
173
+ @fixture_connections.each do |connection|
174
+ connection.rollback_transaction if connection.transaction_open?
175
+ connection.pool.lock_thread = false
176
+ end
177
+ @fixture_connections.clear
178
+ teardown_shared_connection_pool
179
+ else
180
+ ActiveRecord::FixtureSet.reset_cache
181
+ end
182
+
183
+ ActiveRecord::Base.clear_active_connections!
184
+ end
185
+
186
+ def enlist_fixture_connections
187
+ setup_shared_connection_pool
188
+
189
+ ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
190
+ end
191
+
192
+ private
193
+ # Shares the writing connection pool with connections on
194
+ # other handlers.
195
+ #
196
+ # In an application with a primary and replica the test fixtures
197
+ # need to share a connection pool so that the reading connection
198
+ # can see data in the open transaction on the writing connection.
199
+ def setup_shared_connection_pool
200
+ if ActiveRecord::Base.legacy_connection_handling
201
+ writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
202
+
203
+ ActiveRecord::Base.connection_handlers.values.each do |handler|
204
+ if handler != writing_handler
205
+ handler.connection_pool_names.each do |name|
206
+ writing_pool_manager = writing_handler.send(:owner_to_pool_manager)[name]
207
+ return unless writing_pool_manager
208
+
209
+ pool_manager = handler.send(:owner_to_pool_manager)[name]
210
+ @legacy_saved_pool_configs[handler][name] ||= {}
211
+ pool_manager.shard_names.each do |shard_name|
212
+ writing_pool_config = writing_pool_manager.get_pool_config(nil, shard_name)
213
+ pool_config = pool_manager.get_pool_config(nil, shard_name)
214
+ next if pool_config == writing_pool_config
215
+
216
+ @legacy_saved_pool_configs[handler][name][shard_name] = pool_config
217
+ pool_manager.set_pool_config(nil, shard_name, writing_pool_config)
218
+ end
219
+ end
220
+ end
221
+ end
222
+ else
223
+ handler = ActiveRecord::Base.connection_handler
224
+
225
+ handler.connection_pool_names.each do |name|
226
+ pool_manager = handler.send(:owner_to_pool_manager)[name]
227
+ pool_manager.shard_names.each do |shard_name|
228
+ writing_pool_config = pool_manager.get_pool_config(ActiveRecord::Base.writing_role, shard_name)
229
+ @saved_pool_configs[name][shard_name] ||= {}
230
+ pool_manager.role_names.each do |role|
231
+ next unless pool_config = pool_manager.get_pool_config(role, shard_name)
232
+ next if pool_config == writing_pool_config
233
+
234
+ @saved_pool_configs[name][shard_name][role] = pool_config
235
+ pool_manager.set_pool_config(role, shard_name, writing_pool_config)
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+ def teardown_shared_connection_pool
243
+ if ActiveRecord::Base.legacy_connection_handling
244
+ @legacy_saved_pool_configs.each_pair do |handler, names|
245
+ names.each_pair do |name, shards|
246
+ shards.each_pair do |shard_name, pool_config|
247
+ pool_manager = handler.send(:owner_to_pool_manager)[name]
248
+ pool_manager.set_pool_config(nil, shard_name, pool_config)
249
+ end
250
+ end
251
+ end
252
+ else
253
+ handler = ActiveRecord::Base.connection_handler
254
+
255
+ @saved_pool_configs.each_pair do |name, shards|
256
+ pool_manager = handler.send(:owner_to_pool_manager)[name]
257
+ shards.each_pair do |shard_name, roles|
258
+ roles.each_pair do |role, pool_config|
259
+ next unless pool_manager.get_pool_config(role, shard_name)
260
+
261
+ pool_manager.set_pool_config(role, shard_name, pool_config)
262
+ end
263
+ end
264
+ end
265
+ end
266
+
267
+ @legacy_saved_pool_configs.clear
268
+ @saved_pool_configs.clear
269
+ end
270
+
271
+ def load_fixtures(config)
272
+ ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name)
273
+ end
274
+
275
+ def instantiate_fixtures
276
+ if pre_loaded_fixtures
277
+ raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
278
+ ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
279
+ else
280
+ raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
281
+ @loaded_fixtures.each_value do |fixture_set|
282
+ ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
283
+ end
284
+ end
285
+ end
286
+
287
+ def load_instances?
288
+ use_instantiated_fixtures != :no_instances
289
+ end
290
+ end
291
+ end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Timestamp
4
+ # = Active Record \Timestamp
3
5
  #
4
6
  # Active Record automatically timestamps create and update operations if the
5
7
  # table has fields named <tt>created_at/created_on</tt> or
@@ -15,14 +17,25 @@ module ActiveRecord
15
17
  #
16
18
  # == Time Zone aware attributes
17
19
  #
18
- # By default, ActiveRecord::Base keeps all the datetime columns time zone aware by executing following code.
20
+ # Active Record keeps all the <tt>datetime</tt> and <tt>time</tt> columns
21
+ # timezone aware. By default, these values are stored in the database as UTC
22
+ # and converted back to the current <tt>Time.zone</tt> when pulled from the database.
23
+ #
24
+ # This feature can be turned off completely by setting:
25
+ #
26
+ # config.active_record.time_zone_aware_attributes = false
27
+ #
28
+ # You can also specify that only <tt>datetime</tt> columns should be time-zone
29
+ # aware (while <tt>time</tt> should not) by setting:
30
+ #
31
+ # ActiveRecord::Base.time_zone_aware_types = [:datetime]
19
32
  #
20
- # config.active_record.time_zone_aware_attributes = true
33
+ # You can also add database specific timezone aware types. For example, for PostgreSQL:
21
34
  #
22
- # This feature can easily be turned off by assigning value <tt>false</tt> .
35
+ # ActiveRecord::Base.time_zone_aware_types += [:tsrange, :tstzrange]
23
36
  #
24
- # If your attributes are time zone aware and you desire to skip time zone conversion to the current Time.zone
25
- # when reading certain attributes then you can do following:
37
+ # Finally, you can indicate specific attributes of a model for which time zone
38
+ # conversion should not applied, for instance by setting:
26
39
  #
27
40
  # class Topic < ActiveRecord::Base
28
41
  # self.skip_time_zone_conversion_for_attributes = [:written_on]
@@ -31,8 +44,7 @@ module ActiveRecord
31
44
  extend ActiveSupport::Concern
32
45
 
33
46
  included do
34
- class_attribute :record_timestamps
35
- self.record_timestamps = true
47
+ class_attribute :record_timestamps, default: true
36
48
  end
37
49
 
38
50
  def initialize_dup(other) # :nodoc:
@@ -40,81 +52,112 @@ module ActiveRecord
40
52
  clear_timestamp_attributes
41
53
  end
42
54
 
43
- private
55
+ module ClassMethods # :nodoc:
56
+ def touch_attributes_with_time(*names, time: nil)
57
+ attribute_names = timestamp_attributes_for_update_in_model
58
+ attribute_names |= names.map(&:to_s)
59
+ attribute_names.index_with(time || current_time_from_proper_timezone)
60
+ end
61
+
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
44
66
 
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
+
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
80
+
81
+ private
82
+ def timestamp_attributes_for_create
83
+ ["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
84
+ end
85
+
86
+ def timestamp_attributes_for_update
87
+ ["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
88
+ end
89
+
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
95
+ end
96
+ end
97
+
98
+ private
45
99
  def _create_record
46
- if self.record_timestamps
100
+ if record_timestamps
47
101
  current_time = current_time_from_proper_timezone
48
102
 
49
- all_timestamp_attributes.each do |column|
50
- column = column.to_s
51
- if has_attribute?(column) && !attribute_present?(column)
52
- write_attribute(column, current_time)
53
- end
103
+ all_timestamp_attributes_in_model.each do |column|
104
+ _write_attribute(column, current_time) unless _read_attribute(column)
54
105
  end
55
106
  end
56
107
 
57
108
  super
58
109
  end
59
110
 
60
- def _update_record(*args)
61
- if should_record_timestamps?
111
+ def _update_record
112
+ if @_touch_record && should_record_timestamps?
62
113
  current_time = current_time_from_proper_timezone
63
114
 
64
115
  timestamp_attributes_for_update_in_model.each do |column|
65
- column = column.to_s
66
- next if attribute_changed?(column)
67
- write_attribute(column, current_time)
116
+ next if will_save_change_to_attribute?(column)
117
+ _write_attribute(column, current_time)
68
118
  end
69
119
  end
120
+
121
+ super
122
+ end
123
+
124
+ def create_or_update(touch: true, **)
125
+ @_touch_record = touch
70
126
  super
71
127
  end
72
128
 
73
129
  def should_record_timestamps?
74
- self.record_timestamps && (!partial_writes? || changed?)
130
+ record_timestamps && (!partial_writes? || has_changes_to_save?)
75
131
  end
76
132
 
77
133
  def timestamp_attributes_for_create_in_model
78
- timestamp_attributes_for_create.select { |c| self.class.column_names.include?(c.to_s) }
134
+ self.class.timestamp_attributes_for_create_in_model
79
135
  end
80
136
 
81
137
  def timestamp_attributes_for_update_in_model
82
- timestamp_attributes_for_update.select { |c| self.class.column_names.include?(c.to_s) }
138
+ self.class.timestamp_attributes_for_update_in_model
83
139
  end
84
140
 
85
141
  def all_timestamp_attributes_in_model
86
- timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model
142
+ self.class.all_timestamp_attributes_in_model
87
143
  end
88
144
 
89
- def timestamp_attributes_for_update
90
- [:updated_at, :updated_on]
91
- end
92
-
93
- def timestamp_attributes_for_create
94
- [:created_at, :created_on]
95
- end
96
-
97
- def all_timestamp_attributes
98
- timestamp_attributes_for_create + timestamp_attributes_for_update
145
+ def current_time_from_proper_timezone
146
+ self.class.current_time_from_proper_timezone
99
147
  end
100
148
 
101
- def max_updated_column_timestamp(timestamp_names = timestamp_attributes_for_update)
102
- timestamp_names
103
- .map { |attr| self[attr] }
149
+ def max_updated_column_timestamp
150
+ timestamp_attributes_for_update_in_model
151
+ .map { |attr| self[attr]&.to_time }
104
152
  .compact
105
- .map(&:to_time)
106
153
  .max
107
154
  end
108
155
 
109
- def current_time_from_proper_timezone
110
- self.class.default_timezone == :utc ? Time.now.utc : Time.now
111
- end
112
-
113
156
  # Clear attributes and changed_attributes
114
157
  def clear_timestamp_attributes
115
158
  all_timestamp_attributes_in_model.each do |attribute_name|
116
159
  self[attribute_name] = nil
117
- clear_attribute_changes([attribute_name])
160
+ clear_attribute_change(attribute_name)
118
161
  end
119
162
  end
120
163
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ # = Active Record Touch Later
5
+ module TouchLater # :nodoc:
6
+ def before_committed!
7
+ touch_deferred_attributes if has_defer_touch_attrs? && persisted?
8
+ super
9
+ end
10
+
11
+ def touch_later(*names) # :nodoc:
12
+ _raise_record_not_touched_error unless persisted?
13
+
14
+ @_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
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
+
20
+ @_touch_time = current_time_from_proper_timezone
21
+
22
+ surreptitiously_touch @_defer_touch_attrs
23
+ add_to_transaction
24
+ @_new_record_before_last_commit ||= false
25
+
26
+ # touch the parents as we are not calling the after_save callbacks
27
+ self.class.reflect_on_all_associations(:belongs_to).each do |r|
28
+ if touch = r.options[:touch]
29
+ ActiveRecord::Associations::Builder::BelongsTo.touch_record(self, changes_to_save, r.foreign_key, r.name, touch, :touch_later)
30
+ end
31
+ end
32
+ end
33
+
34
+ def touch(*names, time: nil) # :nodoc:
35
+ if has_defer_touch_attrs?
36
+ names |= @_defer_touch_attrs
37
+ super(*names, time: time)
38
+ @_defer_touch_attrs, @_touch_time = nil, nil
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+ private
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
50
+ end
51
+
52
+ def touch_deferred_attributes
53
+ @_skip_dirty_tracking = true
54
+ touch(time: @_touch_time)
55
+ end
56
+
57
+ def has_defer_touch_attrs?
58
+ defined?(@_defer_touch_attrs) && @_defer_touch_attrs.present?
59
+ end
60
+
61
+ def belongs_to_touch_method
62
+ :touch_later
63
+ end
64
+ end
65
+ end