activerecord 4.2.9 → 6.1.4.1

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 (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +964 -1382
  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 +266 -251
  8. data/lib/active_record/association_relation.rb +40 -15
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +162 -69
  11. data/lib/active_record/associations/association_scope.rb +105 -130
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -65
  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 -37
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +49 -66
  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 +148 -287
  22. data/lib/active_record/associations/collection_proxy.rb +252 -150
  23. data/lib/active_record/associations/foreign_association.rb +23 -1
  24. data/lib/active_record/associations/has_many_association.rb +56 -98
  25. data/lib/active_record/associations/has_many_through_association.rb +68 -89
  26. data/lib/active_record/associations/has_one_association.rb +73 -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 -81
  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 +174 -169
  32. data/lib/active_record/associations/preloader/association.rb +108 -115
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +97 -94
  35. data/lib/active_record/associations/singular_association.rb +18 -39
  36. data/lib/active_record/associations/through_association.rb +39 -19
  37. data/lib/active_record/associations.rb +1845 -1598
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +18 -10
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -148
  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 +55 -36
  46. data/lib/active_record/attribute_methods/write.rb +24 -55
  47. data/lib/active_record/attribute_methods.rb +149 -154
  48. data/lib/active_record/attributes.rb +234 -78
  49. data/lib/active_record/autosave_association.rb +133 -60
  50. data/lib/active_record/base.rb +46 -46
  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 +34 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -323
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +292 -124
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +177 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +8 -6
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +473 -255
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +869 -286
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +257 -91
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +483 -230
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +557 -640
  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 +194 -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 +268 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +80 -192
  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 +75 -160
  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 -58
  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 +4 -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 +14 -19
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  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 -5
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  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 +145 -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 +496 -298
  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 +588 -375
  119. data/lib/active_record/connection_adapters/schema_cache.rb +167 -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 +144 -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 -373
  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 +458 -241
  133. data/lib/active_record/counter_cache.rb +70 -49
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -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 +272 -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 +211 -92
  143. data/lib/active_record/errors.rb +224 -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 +10 -5
  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 +275 -500
  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 +62 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +27 -5
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +98 -92
  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 +295 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +673 -325
  170. data/lib/active_record/model_schema.rb +418 -113
  171. data/lib/active_record/nested_attributes.rb +263 -224
  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 +572 -136
  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 +170 -51
  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 +523 -199
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +454 -291
  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 +324 -249
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +316 -242
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +95 -103
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -26
  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 +136 -122
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -413
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +18 -20
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -343
  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 -23
  209. data/lib/active_record/scoping/default.rb +96 -83
  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 +128 -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 +364 -130
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +67 -113
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +86 -49
  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 +287 -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 +182 -163
  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 -45
  231. data/lib/active_record/type/date_time.rb +4 -49
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  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 +27 -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 +63 -56
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +42 -29
  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 -4
  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/model/templates/{module.rb → module.rb.tt} +0 -0
  339. data/lib/rails/generators/active_record.rb +7 -5
  340. metadata +172 -65
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -163
  349. data/lib/active_record/attribute_decorators.rb +0 -66
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/attribute_set.rb +0 -81
  352. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  353. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  354. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  355. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  356. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  357. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  358. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  359. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  360. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  361. data/lib/active_record/type/big_integer.rb +0 -13
  362. data/lib/active_record/type/binary.rb +0 -50
  363. data/lib/active_record/type/boolean.rb +0 -31
  364. data/lib/active_record/type/decimal.rb +0 -64
  365. data/lib/active_record/type/decorator.rb +0 -14
  366. data/lib/active_record/type/float.rb +0 -19
  367. data/lib/active_record/type/integer.rb +0 -59
  368. data/lib/active_record/type/mutable.rb +0 -16
  369. data/lib/active_record/type/numeric.rb +0 -36
  370. data/lib/active_record/type/string.rb +0 -40
  371. data/lib/active_record/type/time_value.rb +0 -38
  372. data/lib/active_record/type/value.rb +0 -110
  373. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  374. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- class AssociationRelation < Relation
3
- def initialize(klass, table, association)
4
- super(klass, table)
4
+ class AssociationRelation < Relation # :nodoc:
5
+ def initialize(klass, association, **)
6
+ super(klass)
5
7
  @association = association
6
8
  end
7
9
 
@@ -10,26 +12,49 @@ module ActiveRecord
10
12
  end
11
13
 
12
14
  def ==(other)
13
- other == to_a
15
+ other == records
14
16
  end
15
17
 
16
- def build(*args, &block)
17
- scoping { @association.build(*args, &block) }
18
- end
19
- alias new build
18
+ %w(insert insert_all insert! insert_all! upsert upsert_all).each do |method|
19
+ class_eval <<~RUBY
20
+ def #{method}(attributes, **kwargs)
21
+ if @association.reflection.through_reflection?
22
+ raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
23
+ end
20
24
 
21
- def create(*args, &block)
22
- scoping { @association.create(*args, &block) }
25
+ scoping { klass.#{method}(attributes, **kwargs) }
26
+ end
27
+ RUBY
23
28
  end
24
29
 
25
- def create!(*args, &block)
26
- scoping { @association.create!(*args, &block) }
30
+ def build(attributes = nil, &block)
31
+ if attributes.is_a?(Array)
32
+ attributes.collect { |attr| build(attr, &block) }
33
+ else
34
+ block = current_scope_restoring_block(&block)
35
+ scoping { _new(attributes, &block) }
36
+ end
27
37
  end
38
+ alias new build
28
39
 
29
40
  private
41
+ def _new(attributes, &block)
42
+ @association.build(attributes, &block)
43
+ end
30
44
 
31
- def exec_queries
32
- super.each { |r| @association.set_inverse_instance r }
33
- end
45
+ def _create(attributes, &block)
46
+ @association.create(attributes, &block)
47
+ end
48
+
49
+ def _create!(attributes, &block)
50
+ @association.create!(attributes, &block)
51
+ end
52
+
53
+ def exec_queries
54
+ super do |record|
55
+ @association.set_inverse_instance_from_queries(record)
56
+ yield record if block_given?
57
+ end
58
+ end
34
59
  end
35
60
  end
@@ -1,49 +1,44 @@
1
- require 'active_support/core_ext/string/conversions'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
2
4
 
3
5
  module ActiveRecord
4
6
  module Associations
5
- # Keeps track of table aliases for ActiveRecord::Associations::ClassMethods::JoinDependency and
6
- # ActiveRecord::Associations::ThroughAssociationScope
7
+ # Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
7
8
  class AliasTracker # :nodoc:
8
- attr_reader :aliases, :connection
9
-
10
- def self.empty(connection)
11
- new connection, Hash.new(0)
12
- end
13
-
14
- def self.create(connection, table_joins)
15
- if table_joins.empty?
16
- empty connection
9
+ def self.create(connection, initial_table, joins, aliases = nil)
10
+ if joins.empty?
11
+ aliases ||= Hash.new(0)
12
+ elsif aliases
13
+ default_proc = aliases.default_proc || proc { 0 }
14
+ aliases.default_proc = proc { |h, k|
15
+ h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
16
+ }
17
17
  else
18
- aliases = Hash.new { |h,k|
19
- h[k] = initial_count_for(connection, k, table_joins)
18
+ aliases = Hash.new { |h, k|
19
+ h[k] = initial_count_for(connection, k, joins)
20
20
  }
21
- new connection, aliases
22
21
  end
22
+ aliases[initial_table] = 1
23
+ new(connection, aliases)
23
24
  end
24
25
 
25
26
  def self.initial_count_for(connection, name, table_joins)
26
- # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
27
- quoted_name = connection.quote_table_name(name).downcase
27
+ quoted_name = nil
28
28
 
29
29
  counts = table_joins.map do |join|
30
30
  if join.is_a?(Arel::Nodes::StringJoin)
31
+ # quoted_name should be case ignored as some database adapters (Oracle) return quoted name in uppercase
32
+ quoted_name ||= connection.quote_table_name(name)
33
+
31
34
  # Table names + table aliases
32
- join.left.downcase.scan(
33
- /join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/
35
+ join.left.scan(
36
+ /JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name}|#{name})\sON/i
34
37
  ).size
35
- elsif join.respond_to? :left
36
- join.left.table_name == name ? 1 : 0
38
+ elsif join.is_a?(Arel::Nodes::Join)
39
+ join.left.name == name ? 1 : 0
37
40
  else
38
- # this branch is reached by two tests:
39
- #
40
- # activerecord/test/cases/associations/cascaded_eager_loading_test.rb:37
41
- # with :posts
42
- #
43
- # activerecord/test/cases/associations/eager_test.rb:1133
44
- # with :comments
45
- #
46
- 0
41
+ raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
47
42
  end
48
43
  end
49
44
 
@@ -56,31 +51,33 @@ module ActiveRecord
56
51
  @connection = connection
57
52
  end
58
53
 
59
- def aliased_table_for(table_name, aliased_name)
60
- if aliases[table_name].zero?
54
+ def aliased_table_for(arel_table, table_name = nil)
55
+ table_name ||= arel_table.name
56
+
57
+ if aliases[table_name] == 0
61
58
  # If it's zero, we can have our table_name
62
59
  aliases[table_name] = 1
63
- Arel::Table.new(table_name)
60
+ arel_table = arel_table.alias(table_name) if arel_table.name != table_name
64
61
  else
65
62
  # Otherwise, we need to use an alias
66
- aliased_name = connection.table_alias_for(aliased_name)
63
+ aliased_name = @connection.table_alias_for(yield)
67
64
 
68
65
  # Update the count
69
- aliases[aliased_name] += 1
66
+ count = aliases[aliased_name] += 1
70
67
 
71
- table_alias = if aliases[aliased_name] > 1
72
- "#{truncate(aliased_name)}_#{aliases[aliased_name]}"
73
- else
74
- aliased_name
75
- end
76
- Arel::Table.new(table_name).alias(table_alias)
68
+ aliased_name = "#{truncate(aliased_name)}_#{count}" if count > 1
69
+
70
+ arel_table = arel_table.alias(aliased_name)
77
71
  end
72
+
73
+ arel_table
78
74
  end
79
75
 
80
- private
76
+ attr_reader :aliases
81
77
 
78
+ private
82
79
  def truncate(name)
83
- name.slice(0, connection.table_alias_length - 2)
80
+ name.slice(0, @connection.table_alias_length - 2)
84
81
  end
85
82
  end
86
83
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/array/wrap'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
4
  module Associations
@@ -8,18 +8,34 @@ module ActiveRecord
8
8
  #
9
9
  # Association
10
10
  # SingularAssociation
11
- # HasOneAssociation
11
+ # HasOneAssociation + ForeignAssociation
12
12
  # HasOneThroughAssociation + ThroughAssociation
13
13
  # BelongsToAssociation
14
14
  # BelongsToPolymorphicAssociation
15
15
  # CollectionAssociation
16
- # HasManyAssociation
16
+ # HasManyAssociation + ForeignAssociation
17
17
  # HasManyThroughAssociation + ThroughAssociation
18
+ #
19
+ # Associations in Active Record are middlemen between the object that
20
+ # holds the association, known as the <tt>owner</tt>, and the associated
21
+ # result set, known as the <tt>target</tt>. Association metadata is available in
22
+ # <tt>reflection</tt>, which is an instance of <tt>ActiveRecord::Reflection::AssociationReflection</tt>.
23
+ #
24
+ # For example, given
25
+ #
26
+ # class Blog < ActiveRecord::Base
27
+ # has_many :posts
28
+ # end
29
+ #
30
+ # blog = Blog.first
31
+ #
32
+ # The association of <tt>blog.posts</tt> has the object +blog+ as its
33
+ # <tt>owner</tt>, the collection of its posts as <tt>target</tt>, and
34
+ # the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
18
35
  class Association #:nodoc:
19
36
  attr_reader :owner, :target, :reflection
20
- attr_accessor :inversed
21
37
 
22
- delegate :options, :to => :reflection
38
+ delegate :options, to: :reflection
23
39
 
24
40
  def initialize(owner, reflection)
25
41
  reflection.check_validity!
@@ -30,14 +46,6 @@ module ActiveRecord
30
46
  reset_scope
31
47
  end
32
48
 
33
- # Returns the name of the table of the associated class:
34
- #
35
- # post.comments.aliased_table_name # => "comments"
36
- #
37
- def aliased_table_name
38
- klass.table_name
39
- end
40
-
41
49
  # Resets the \loaded flag to +false+ and sets the \target to +nil+.
42
50
  def reset
43
51
  @loaded = false
@@ -46,8 +54,14 @@ module ActiveRecord
46
54
  @inversed = false
47
55
  end
48
56
 
57
+ def reset_negative_cache # :nodoc:
58
+ reset if loaded? && target.nil?
59
+ end
60
+
49
61
  # Reloads the \target and returns +self+ on success.
50
- def reload
62
+ # The QueryCache is cleared if +force+ is true.
63
+ def reload(force = false)
64
+ klass.connection.clear_query_cache if force && klass
51
65
  reset
52
66
  reset_scope
53
67
  load_target
@@ -73,7 +87,7 @@ module ActiveRecord
73
87
  #
74
88
  # Note that if the target has not been loaded, it is not considered stale.
75
89
  def stale_target?
76
- !inversed && loaded? && @stale_state != stale_state
90
+ !@inversed && loaded? && @stale_state != stale_state
77
91
  end
78
92
 
79
93
  # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -83,18 +97,10 @@ module ActiveRecord
83
97
  end
84
98
 
85
99
  def scope
86
- target_scope.merge(association_scope)
87
- end
88
-
89
- # The scope for this association.
90
- #
91
- # Note that the association_scope is merged into the target_scope only when the
92
- # scope method is called. This is because at that point the call may be surrounded
93
- # by scope.scoping { ... } or with_scope { ... } etc, which affects the scope which
94
- # actually gets built.
95
- def association_scope
96
- if klass
97
- @association_scope ||= AssociationScope.scope(self, klass.connection)
100
+ if (scope = klass.current_scope) && scope.try(:proxy_association) == self
101
+ scope.spawn
102
+ else
103
+ target_scope.merge!(association_scope)
98
104
  end
99
105
  end
100
106
 
@@ -104,24 +110,54 @@ module ActiveRecord
104
110
 
105
111
  # Set the inverse association, if possible
106
112
  def set_inverse_instance(record)
107
- if invertible_for?(record)
108
- inverse = record.association(inverse_reflection_for(record).name)
109
- inverse.target = owner
110
- inverse.inversed = true
113
+ if inverse = inverse_association_for(record)
114
+ inverse.inversed_from(owner)
111
115
  end
112
116
  record
113
117
  end
114
118
 
119
+ def set_inverse_instance_from_queries(record)
120
+ if inverse = inverse_association_for(record)
121
+ inverse.inversed_from_queries(owner)
122
+ end
123
+ record
124
+ end
125
+
126
+ # Remove the inverse association, if possible
127
+ def remove_inverse_instance(record)
128
+ if inverse = inverse_association_for(record)
129
+ inverse.inversed_from(nil)
130
+ end
131
+ end
132
+
133
+ def inversed_from(record)
134
+ self.target = record
135
+ @inversed = !!record
136
+ end
137
+
138
+ def inversed_from_queries(record)
139
+ if inversable?(record)
140
+ self.target = record
141
+ @inversed = true
142
+ else
143
+ @inversed = false
144
+ end
145
+ end
146
+
115
147
  # Returns the class of the target. belongs_to polymorphic overrides this to look at the
116
148
  # polymorphic_type field on the owner.
117
149
  def klass
118
150
  reflection.klass
119
151
  end
120
152
 
121
- # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
122
- # through association's scope)
123
- def target_scope
124
- AssociationRelation.create(klass, klass.arel_table, self).merge!(klass.all)
153
+ def extensions
154
+ extensions = klass.default_extensions | reflection.extensions
155
+
156
+ if reflection.scope
157
+ extensions |= reflection.scope_for(klass.unscoped, owner).extensions
158
+ end
159
+
160
+ extensions
125
161
  end
126
162
 
127
163
  # Loads the \target if needed and returns it.
@@ -143,17 +179,9 @@ module ActiveRecord
143
179
  reset
144
180
  end
145
181
 
146
- def interpolate(sql, record = nil)
147
- if sql.respond_to?(:to_proc)
148
- owner.instance_exec(record, &sql)
149
- else
150
- sql
151
- end
152
- end
153
-
154
- # We can't dump @reflection since it contains the scope proc
182
+ # We can't dump @reflection and @through_reflection since it contains the scope proc
155
183
  def marshal_dump
156
- ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
184
+ ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
157
185
  [@reflection.name, ivars]
158
186
  end
159
187
 
@@ -163,36 +191,72 @@ module ActiveRecord
163
191
  @reflection = @owner.class._reflect_on_association(reflection_name)
164
192
  end
165
193
 
166
- def initialize_attributes(record) #:nodoc:
194
+ def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
195
+ except_from_scope_attributes ||= {}
167
196
  skip_assign = [reflection.foreign_key, reflection.type].compact
168
- attributes = create_scope.except(*(record.changed - skip_assign))
169
- record.assign_attributes(attributes)
197
+ assigned_keys = record.changed_attribute_names_to_save
198
+ assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
199
+ attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
200
+ record.send(:_assign_attributes, attributes) if attributes.any?
170
201
  set_inverse_instance(record)
171
202
  end
172
203
 
204
+ def create(attributes = nil, &block)
205
+ _create_record(attributes, &block)
206
+ end
207
+
208
+ def create!(attributes = nil, &block)
209
+ _create_record(attributes, true, &block)
210
+ end
211
+
173
212
  private
213
+ def find_target
214
+ if strict_loading? && owner.validation_context.nil?
215
+ Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
216
+ end
174
217
 
175
- def find_target?
176
- !loaded? && (!owner.new_record? || foreign_key_present?) && klass
218
+ scope = self.scope
219
+ return scope.to_a if skip_statement_cache?(scope)
220
+
221
+ sc = reflection.association_scope_cache(klass, owner) do |params|
222
+ as = AssociationScope.create { params.bind }
223
+ target_scope.merge!(as.scope(self))
224
+ end
225
+
226
+ binds = AssociationScope.get_bind_values(owner, reflection.chain)
227
+ sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
177
228
  end
178
229
 
179
- def creation_attributes
180
- attributes = {}
230
+ def strict_loading?
231
+ return reflection.strict_loading? if reflection.options.key?(:strict_loading)
181
232
 
182
- if (reflection.has_one? || reflection.collection?) && !options[:through]
183
- attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
233
+ owner.strict_loading?
234
+ end
184
235
 
185
- if reflection.options[:as]
186
- attributes[reflection.type] = owner.class.base_class.name
187
- end
236
+ # The scope for this association.
237
+ #
238
+ # Note that the association_scope is merged into the target_scope only when the
239
+ # scope method is called. This is because at that point the call may be surrounded
240
+ # by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
241
+ # actually gets built.
242
+ def association_scope
243
+ if klass
244
+ @association_scope ||= AssociationScope.scope(self)
188
245
  end
246
+ end
189
247
 
190
- attributes
248
+ # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
249
+ # through association's scope)
250
+ def target_scope
251
+ AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
191
252
  end
192
253
 
193
- # Sets the owner attributes on the given record
194
- def set_owner_attributes(record)
195
- creation_attributes.each { |key, value| record[key] = value }
254
+ def scope_for_create
255
+ scope.scope_for_create
256
+ end
257
+
258
+ def find_target?
259
+ !loaded? && (!owner.new_record? || foreign_key_present?) && klass
196
260
  end
197
261
 
198
262
  # Returns true if there is a foreign key present on the owner which
@@ -214,12 +278,19 @@ module ActiveRecord
214
278
  unless record.is_a?(reflection.klass)
215
279
  fresh_class = reflection.class_name.safe_constantize
216
280
  unless fresh_class && record.is_a?(fresh_class)
217
- message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
281
+ message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, "\
282
+ "got #{record.inspect} which is an instance of #{record.class}(##{record.class.object_id})"
218
283
  raise ActiveRecord::AssociationTypeMismatch, message
219
284
  end
220
285
  end
221
286
  end
222
287
 
288
+ def inverse_association_for(record)
289
+ if invertible_for?(record)
290
+ record.association(inverse_reflection_for(record).name)
291
+ end
292
+ end
293
+
223
294
  # Can be redefined by subclasses, notably polymorphic belongs_to
224
295
  # The record parameter is necessary to support polymorphic inverses as we must check for
225
296
  # the association in the specific class of the record.
@@ -235,31 +306,53 @@ module ActiveRecord
235
306
 
236
307
  # Returns true if record contains the foreign_key
237
308
  def foreign_key_for?(record)
238
- record.has_attribute?(reflection.foreign_key)
309
+ record._has_attribute?(reflection.foreign_key)
239
310
  end
240
311
 
241
312
  # This should be implemented to return the values of the relevant key(s) on the owner,
242
313
  # so that when stale_state is different from the value stored on the last find_target,
243
314
  # the target is stale.
244
315
  #
245
- # This is only relevant to certain associations, which is why it returns nil by default.
316
+ # This is only relevant to certain associations, which is why it returns +nil+ by default.
246
317
  def stale_state
247
318
  end
248
319
 
249
320
  def build_record(attributes)
250
321
  reflection.build_association(attributes) do |record|
251
- initialize_attributes(record)
322
+ initialize_attributes(record, attributes)
323
+ yield(record) if block_given?
252
324
  end
253
325
  end
254
326
 
255
327
  # Returns true if statement cache should be skipped on the association reader.
256
- def skip_statement_cache?
257
- reflection.scope_chain.any?(&:any?) ||
328
+ def skip_statement_cache?(scope)
329
+ reflection.has_scope? ||
258
330
  scope.eager_loading? ||
259
- klass.current_scope ||
260
- klass.default_scopes.any? ||
331
+ klass.scope_attributes? ||
261
332
  reflection.source_reflection.active_record.default_scopes.any?
262
333
  end
334
+
335
+ def enqueue_destroy_association(options)
336
+ job_class = owner.class.destroy_association_async_job
337
+
338
+ if job_class
339
+ owner._after_commit_jobs.push([job_class, options])
340
+ end
341
+ end
342
+
343
+ def inversable?(record)
344
+ record &&
345
+ ((!record.persisted? || !owner.persisted?) || matches_foreign_key?(record))
346
+ end
347
+
348
+ def matches_foreign_key?(record)
349
+ if foreign_key_for?(record)
350
+ record.read_attribute(reflection.foreign_key) == owner.id ||
351
+ (foreign_key_for?(owner) && owner.read_attribute(reflection.foreign_key) == record.id)
352
+ else
353
+ owner.read_attribute(reflection.foreign_key) == record.id
354
+ end
355
+ end
263
356
  end
264
357
  end
265
358
  end