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,5 +1,6 @@
1
- require 'thread'
2
- require 'active_support/core_ext/string/filters'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/filters"
3
4
 
4
5
  module ActiveRecord
5
6
  # = Active Record Reflection
@@ -7,42 +8,46 @@ module ActiveRecord
7
8
  extend ActiveSupport::Concern
8
9
 
9
10
  included do
10
- class_attribute :_reflections, instance_writer: false
11
- class_attribute :aggregate_reflections, instance_writer: false
12
- self._reflections = {}
13
- self.aggregate_reflections = {}
11
+ class_attribute :_reflections, instance_writer: false, default: {}
12
+ class_attribute :aggregate_reflections, instance_writer: false, default: {}
14
13
  end
15
14
 
16
- def self.create(macro, name, scope, options, ar)
17
- klass = case macro
18
- when :composed_of
19
- AggregateReflection
20
- when :has_many
21
- HasManyReflection
22
- when :has_one
23
- HasOneReflection
24
- when :belongs_to
25
- BelongsToReflection
26
- else
27
- raise "Unsupported Macro: #{macro}"
28
- end
29
-
30
- reflection = klass.new(name, scope, options, ar)
31
- options[:through] ? ThroughReflection.new(reflection) : reflection
32
- end
15
+ class << self
16
+ def create(macro, name, scope, options, ar)
17
+ reflection = reflection_class_for(macro).new(name, scope, options, ar)
18
+ options[:through] ? ThroughReflection.new(reflection) : reflection
19
+ end
33
20
 
34
- def self.add_reflection(ar, name, reflection)
35
- ar.clear_reflections_cache
36
- ar._reflections = ar._reflections.merge(name.to_s => reflection)
37
- end
21
+ def add_reflection(ar, name, reflection)
22
+ ar.clear_reflections_cache
23
+ name = -name.to_s
24
+ ar._reflections = ar._reflections.except(name).merge!(name => reflection)
25
+ end
38
26
 
39
- def self.add_aggregate_reflection(ar, name, reflection)
40
- ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
27
+ def add_aggregate_reflection(ar, name, reflection)
28
+ ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
29
+ end
30
+
31
+ private
32
+ def reflection_class_for(macro)
33
+ case macro
34
+ when :composed_of
35
+ AggregateReflection
36
+ when :has_many
37
+ HasManyReflection
38
+ when :has_one
39
+ HasOneReflection
40
+ when :belongs_to
41
+ BelongsToReflection
42
+ else
43
+ raise "Unsupported Macro: #{macro}"
44
+ end
45
+ end
41
46
  end
42
47
 
43
- # \Reflection enables interrogating of Active Record classes and objects
44
- # about their associations and aggregations. This information can,
45
- # for example, be used in a form builder that takes an Active Record object
48
+ # \Reflection enables the ability to examine the associations and aggregations of
49
+ # Active Record classes and objects. This information, for example,
50
+ # can be used in a form builder that takes an Active Record object
46
51
  # and creates input fields for all of the attributes depending on their type
47
52
  # and displays the associations to other objects.
48
53
  #
@@ -62,20 +67,20 @@ module ActiveRecord
62
67
  aggregate_reflections[aggregation.to_s]
63
68
  end
64
69
 
65
- # Returns a Hash of name of the reflection as the key and a AssociationReflection as the value.
70
+ # Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
66
71
  #
67
72
  # Account.reflections # => {"balance" => AggregateReflection}
68
73
  #
69
- # @api public
70
74
  def reflections
71
75
  @__reflections ||= begin
72
76
  ref = {}
73
77
 
74
78
  _reflections.each do |name, reflection|
75
- parent_name, parent_reflection = reflection.parent_reflection
79
+ parent_reflection = reflection.parent_reflection
76
80
 
77
- if parent_name
78
- ref[parent_name] = parent_reflection
81
+ if parent_reflection
82
+ parent_name = parent_reflection.name
83
+ ref[parent_name.to_s] = parent_reflection
79
84
  else
80
85
  ref[name] = reflection
81
86
  end
@@ -95,10 +100,10 @@ module ActiveRecord
95
100
  # Account.reflect_on_all_associations # returns an array of all associations
96
101
  # Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
97
102
  #
98
- # @api public
99
103
  def reflect_on_all_associations(macro = nil)
100
104
  association_reflections = reflections.values
101
- macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
105
+ association_reflections.select! { |reflection| reflection.macro == macro } if macro
106
+ association_reflections
102
107
  end
103
108
 
104
109
  # Returns the AssociationReflection object for the +association+ (use the symbol).
@@ -106,31 +111,42 @@ module ActiveRecord
106
111
  # Account.reflect_on_association(:owner) # returns the owner AssociationReflection
107
112
  # Invoice.reflect_on_association(:line_items).macro # returns :has_many
108
113
  #
109
- # @api public
110
114
  def reflect_on_association(association)
111
115
  reflections[association.to_s]
112
116
  end
113
117
 
114
- # @api private
115
118
  def _reflect_on_association(association) #:nodoc:
116
119
  _reflections[association.to_s]
117
120
  end
118
121
 
119
122
  # Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
120
- #
121
- # @api public
122
123
  def reflect_on_all_autosave_associations
123
124
  reflections.values.select { |reflection| reflection.options[:autosave] }
124
125
  end
125
126
 
126
- def clear_reflections_cache #:nodoc:
127
+ def clear_reflections_cache # :nodoc:
127
128
  @__reflections = nil
128
129
  end
129
130
  end
130
131
 
131
- # Holds all the methods that are shared between MacroReflection, AssociationReflection
132
- # and ThroughReflection
132
+ # Holds all the methods that are shared between MacroReflection and ThroughReflection.
133
+ #
134
+ # AbstractReflection
135
+ # MacroReflection
136
+ # AggregateReflection
137
+ # AssociationReflection
138
+ # HasManyReflection
139
+ # HasOneReflection
140
+ # BelongsToReflection
141
+ # HasAndBelongsToManyReflection
142
+ # ThroughReflection
143
+ # PolymorphicReflection
144
+ # RuntimeReflection
133
145
  class AbstractReflection # :nodoc:
146
+ def through_reflection?
147
+ false
148
+ end
149
+
134
150
  def table_name
135
151
  klass.table_name
136
152
  end
@@ -141,35 +157,70 @@ module ActiveRecord
141
157
  klass.new(attributes, &block)
142
158
  end
143
159
 
144
- def quoted_table_name
145
- klass.quoted_table_name
146
- end
147
-
148
- def primary_key_type
149
- klass.type_for_attribute(klass.primary_key)
150
- end
151
-
152
160
  # Returns the class name for the macro.
153
161
  #
154
162
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
155
163
  # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
156
164
  def class_name
157
- @class_name ||= (options[:class_name] || derive_class_name).to_s
165
+ @class_name ||= -(options[:class_name] || derive_class_name).to_s
166
+ end
167
+
168
+ # Returns a list of scopes that should be applied for this Reflection
169
+ # object when querying the database.
170
+ def scopes
171
+ scope ? [scope] : []
158
172
  end
159
173
 
160
- JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
174
+ def join_scope(table, foreign_table, foreign_klass)
175
+ predicate_builder = predicate_builder(table)
176
+ scope_chain_items = join_scopes(table, predicate_builder)
177
+ klass_scope = klass_join_scope(table, predicate_builder)
178
+
179
+ if type
180
+ klass_scope.where!(type => foreign_klass.polymorphic_name)
181
+ end
182
+
183
+ scope_chain_items.inject(klass_scope, &:merge!)
184
+
185
+ primary_key = join_primary_key
186
+ foreign_key = join_foreign_key
187
+
188
+ klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
189
+
190
+ if klass.finder_needs_type_condition?
191
+ klass_scope.where!(klass.send(:type_condition, table))
192
+ end
161
193
 
162
- def join_keys(assoc_klass)
163
- JoinKeys.new(foreign_key, active_record_primary_key)
194
+ klass_scope
164
195
  end
165
196
 
166
- def source_macro
167
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
168
- ActiveRecord::Base.source_macro is deprecated and will be removed
169
- without replacement.
170
- MSG
197
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
198
+ if scope
199
+ [scope_for(build_scope(table, predicate_builder, klass))]
200
+ else
201
+ []
202
+ end
203
+ end
204
+
205
+ def klass_join_scope(table, predicate_builder) # :nodoc:
206
+ relation = build_scope(table, predicate_builder)
207
+ klass.scope_for_association(relation)
208
+ end
171
209
 
172
- macro
210
+ def constraints
211
+ chain.flat_map(&:scopes)
212
+ end
213
+
214
+ def counter_cache_column
215
+ @counter_cache_column ||= if belongs_to?
216
+ if options[:counter_cache] == true
217
+ -"#{active_record.name.demodulize.underscore.pluralize}_count"
218
+ elsif options[:counter_cache]
219
+ -options[:counter_cache].to_s
220
+ end
221
+ else
222
+ -(options[:counter_cache]&.to_s || "#{name}_count")
223
+ end
173
224
  end
174
225
 
175
226
  def inverse_of
@@ -185,17 +236,80 @@ module ActiveRecord
185
236
  end
186
237
  end
187
238
  end
239
+
240
+ # This shit is nasty. We need to avoid the following situation:
241
+ #
242
+ # * An associated record is deleted via record.destroy
243
+ # * Hence the callbacks run, and they find a belongs_to on the record with a
244
+ # :counter_cache options which points back at our owner. So they update the
245
+ # counter cache.
246
+ # * In which case, we must make sure to *not* update the counter cache, or else
247
+ # it will be decremented twice.
248
+ #
249
+ # Hence this method.
250
+ def inverse_which_updates_counter_cache
251
+ return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
252
+ @inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
253
+ inverse.counter_cache_column == counter_cache_column
254
+ end
255
+ end
256
+ alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
257
+
258
+ def inverse_updates_counter_in_memory?
259
+ inverse_of && inverse_which_updates_counter_cache == inverse_of
260
+ end
261
+
262
+ # Returns whether a counter cache should be used for this association.
263
+ #
264
+ # The counter_cache option must be given on either the owner or inverse
265
+ # association, and the column must be present on the owner.
266
+ def has_cached_counter?
267
+ options[:counter_cache] ||
268
+ inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
269
+ active_record.has_attribute?(counter_cache_column)
270
+ end
271
+
272
+ def counter_must_be_updated_by_has_many?
273
+ !inverse_updates_counter_in_memory? && has_cached_counter?
274
+ end
275
+
276
+ def alias_candidate(name)
277
+ "#{plural_name}_#{name}"
278
+ end
279
+
280
+ def chain
281
+ collect_join_chain
282
+ end
283
+
284
+ def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
285
+ Relation.create(
286
+ klass,
287
+ table: table,
288
+ predicate_builder: predicate_builder
289
+ )
290
+ end
291
+
292
+ def strict_loading?
293
+ options[:strict_loading]
294
+ end
295
+
296
+ protected
297
+ def actual_source_reflection # FIXME: this is a horrible name
298
+ self
299
+ end
300
+
301
+ private
302
+ def predicate_builder(table)
303
+ PredicateBuilder.new(TableMetadata.new(klass, table))
304
+ end
305
+
306
+ def primary_key(klass)
307
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
308
+ end
188
309
  end
310
+
189
311
  # Base class for AggregateReflection and AssociationReflection. Objects of
190
312
  # AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
191
- #
192
- # MacroReflection
193
- # AssociationReflection
194
- # AggregateReflection
195
- # HasManyReflection
196
- # HasOneReflection
197
- # BelongsToReflection
198
- # ThroughReflection
199
313
  class MacroReflection < AbstractReflection
200
314
  # Returns the name of the macro.
201
315
  #
@@ -226,9 +340,8 @@ module ActiveRecord
226
340
  end
227
341
 
228
342
  def autosave=(autosave)
229
- @automatic_inverse_of = false
230
343
  @options[:autosave] = autosave
231
- _, parent_reflection = self.parent_reflection
344
+ parent_reflection = self.parent_reflection
232
345
  if parent_reflection
233
346
  parent_reflection.autosave = autosave
234
347
  end
@@ -238,6 +351,17 @@ module ActiveRecord
238
351
  #
239
352
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
240
353
  # <tt>has_many :clients</tt> returns the Client class
354
+ #
355
+ # class Company < ActiveRecord::Base
356
+ # has_many :clients
357
+ # end
358
+ #
359
+ # Company.reflect_on_association(:clients).klass
360
+ # # => Client
361
+ #
362
+ # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
363
+ # a new association object. Use +build_association+ or +create_association+
364
+ # instead. This allows plugins to hook into association object creation.
241
365
  def klass
242
366
  @klass ||= compute_class(class_name)
243
367
  end
@@ -256,14 +380,17 @@ module ActiveRecord
256
380
  active_record == other_aggregation.active_record
257
381
  end
258
382
 
383
+ def scope_for(relation, owner = nil)
384
+ relation.instance_exec(owner, &scope) || relation
385
+ end
386
+
259
387
  private
260
388
  def derive_class_name
261
389
  name.to_s.camelize
262
390
  end
263
391
  end
264
392
 
265
-
266
- # Holds all the meta-data about an aggregation as it was specified in the
393
+ # Holds all the metadata about an aggregation as it was specified in the
267
394
  # Active Record class.
268
395
  class AggregateReflection < MacroReflection #:nodoc:
269
396
  def mapping
@@ -272,50 +399,36 @@ module ActiveRecord
272
399
  end
273
400
  end
274
401
 
275
- # Holds all the meta-data about an association as it was specified in the
402
+ # Holds all the metadata about an association as it was specified in the
276
403
  # Active Record class.
277
404
  class AssociationReflection < MacroReflection #:nodoc:
278
- # Returns the target association's class.
279
- #
280
- # class Author < ActiveRecord::Base
281
- # has_many :books
282
- # end
283
- #
284
- # Author.reflect_on_association(:books).klass
285
- # # => Book
286
- #
287
- # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
288
- # a new association object. Use +build_association+ or +create_association+
289
- # instead. This allows plugins to hook into association object creation.
290
- def klass
291
- @klass ||= compute_class(class_name)
292
- end
293
-
294
405
  def compute_class(name)
406
+ if polymorphic?
407
+ raise ArgumentError, "Polymorphic associations do not support computing the class."
408
+ end
295
409
  active_record.send(:compute_type, name)
296
410
  end
297
411
 
298
412
  attr_reader :type, :foreign_type
299
- attr_accessor :parent_reflection # [:name, Reflection]
413
+ attr_accessor :parent_reflection # Reflection
300
414
 
301
415
  def initialize(name, scope, options, active_record)
302
416
  super
303
- @automatic_inverse_of = nil
304
- @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
305
- @foreign_type = options[:foreign_type] || "#{name}_type"
417
+ @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
418
+ @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
306
419
  @constructable = calculate_constructable(macro, options)
307
- @association_scope_cache = {}
308
- @scope_lock = Mutex.new
420
+
421
+ if options[:class_name] && options[:class_name].class == Class
422
+ raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
423
+ end
309
424
  end
310
425
 
311
- def association_scope_cache(conn, owner)
312
- key = conn.prepared_statements
426
+ def association_scope_cache(klass, owner, &block)
427
+ key = self
313
428
  if polymorphic?
314
429
  key = [key, owner._read_attribute(@foreign_type)]
315
430
  end
316
- @association_scope_cache[key] ||= @scope_lock.synchronize {
317
- @association_scope_cache[key] ||= yield
318
- }
431
+ klass.cached_find_by_statement(key, &block)
319
432
  end
320
433
 
321
434
  def constructable? # :nodoc:
@@ -323,32 +436,31 @@ module ActiveRecord
323
436
  end
324
437
 
325
438
  def join_table
326
- @join_table ||= options[:join_table] || derive_join_table
439
+ @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
327
440
  end
328
441
 
329
442
  def foreign_key
330
- @foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
443
+ @foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
331
444
  end
332
445
 
333
446
  def association_foreign_key
334
- @association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
447
+ @association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
335
448
  end
336
449
 
337
- # klass option is necessary to support loading polymorphic associations
338
450
  def association_primary_key(klass = nil)
339
- options[:primary_key] || primary_key(klass || self.klass)
451
+ primary_key(klass || self.klass)
340
452
  end
341
453
 
342
454
  def active_record_primary_key
343
- @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
455
+ @active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
344
456
  end
345
457
 
346
- def counter_cache_column
347
- if options[:counter_cache] == true
348
- "#{active_record.name.demodulize.underscore.pluralize}_count"
349
- elsif options[:counter_cache]
350
- options[:counter_cache].to_s
351
- end
458
+ def join_primary_key(klass = nil)
459
+ foreign_key
460
+ end
461
+
462
+ def join_foreign_key
463
+ active_record_primary_key
352
464
  end
353
465
 
354
466
  def check_validity!
@@ -358,21 +470,18 @@ module ActiveRecord
358
470
  def check_preloadable!
359
471
  return unless scope
360
472
 
361
- if scope.arity > 0
362
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
473
+ unless scope.arity == 0
474
+ raise ArgumentError, <<-MSG.squish
363
475
  The association scope '#{name}' is instance dependent (the scope
364
- block takes an argument). Preloading happens before the individual
365
- instances are created. This means that there is no instance being
366
- passed to the association scope. This will most likely result in
367
- broken or incorrect behavior. Joining, Preloading and eager loading
368
- of these associations is deprecated and will be removed in the future.
476
+ block takes an argument). Preloading instance dependent scopes is
477
+ not supported.
369
478
  MSG
370
479
  end
371
480
  end
372
481
  alias :check_eager_loadable! :check_preloadable!
373
482
 
374
483
  def join_id_for(owner) # :nodoc:
375
- owner[active_record_primary_key]
484
+ owner[join_foreign_key]
376
485
  end
377
486
 
378
487
  def through_reflection
@@ -385,18 +494,22 @@ module ActiveRecord
385
494
 
386
495
  # A chain of reflections from this one back to the owner. For more see the explanation in
387
496
  # ThroughReflection.
388
- def chain
497
+ def collect_join_chain
389
498
  [self]
390
499
  end
391
500
 
501
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
502
+ # SQL queries on associations.
503
+ def clear_association_scope_cache # :nodoc:
504
+ klass.initialize_find_by_cache
505
+ end
506
+
392
507
  def nested?
393
508
  false
394
509
  end
395
510
 
396
- # An array of arrays of scopes. Each item in the outside array corresponds to a reflection
397
- # in the #chain.
398
- def scope_chain
399
- scope ? [[scope]] : [[]]
511
+ def has_scope?
512
+ scope
400
513
  end
401
514
 
402
515
  def has_inverse?
@@ -444,69 +557,48 @@ module ActiveRecord
444
557
  # Returns +true+ if +self+ is a +has_one+ reflection.
445
558
  def has_one?; false; end
446
559
 
447
- def association_class
448
- case macro
449
- when :belongs_to
450
- if polymorphic?
451
- Associations::BelongsToPolymorphicAssociation
452
- else
453
- Associations::BelongsToAssociation
454
- end
455
- when :has_many
456
- if options[:through]
457
- Associations::HasManyThroughAssociation
458
- else
459
- Associations::HasManyAssociation
460
- end
461
- when :has_one
462
- if options[:through]
463
- Associations::HasOneThroughAssociation
464
- else
465
- Associations::HasOneAssociation
466
- end
467
- end
468
- end
560
+ def association_class; raise NotImplementedError; end
469
561
 
470
562
  def polymorphic?
471
563
  options[:polymorphic]
472
564
  end
473
565
 
474
566
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
475
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
567
+ INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
476
568
 
477
- protected
569
+ def add_as_source(seed)
570
+ seed
571
+ end
478
572
 
479
- def actual_source_reflection # FIXME: this is a horrible name
480
- self
481
- end
573
+ def add_as_polymorphic_through(reflection, seed)
574
+ seed + [PolymorphicReflection.new(self, reflection)]
575
+ end
482
576
 
483
- private
577
+ def add_as_through(seed)
578
+ seed + [self]
579
+ end
484
580
 
581
+ def extensions
582
+ Array(options[:extend])
583
+ end
584
+
585
+ private
485
586
  def calculate_constructable(macro, options)
486
- case macro
487
- when :belongs_to
488
- !polymorphic?
489
- when :has_one
490
- !options[:through]
491
- else
492
- true
493
- end
587
+ true
494
588
  end
495
589
 
496
590
  # Attempts to find the inverse association name automatically.
497
591
  # If it cannot find a suitable inverse association name, it returns
498
- # nil.
592
+ # +nil+.
499
593
  def inverse_name
500
- options.fetch(:inverse_of) do
501
- if @automatic_inverse_of == false
502
- nil
503
- else
504
- @automatic_inverse_of ||= automatic_inverse_of
505
- end
594
+ unless defined?(@inverse_name)
595
+ @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
506
596
  end
597
+
598
+ @inverse_name
507
599
  end
508
600
 
509
- # returns either nil or the inverse association name that it finds.
601
+ # returns either +nil+ or the inverse association name that it finds.
510
602
  def automatic_inverse_of
511
603
  if can_find_inverse_of_automatically?(self)
512
604
  inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
@@ -520,23 +612,19 @@ module ActiveRecord
520
612
  end
521
613
 
522
614
  if valid_inverse_reflection?(reflection)
523
- return inverse_name
615
+ inverse_name
524
616
  end
525
617
  end
526
-
527
- false
528
618
  end
529
619
 
530
620
  # Checks if the inverse reflection that is returned from the
531
621
  # +automatic_inverse_of+ method is a valid reflection. We must
532
622
  # make sure that the reflection's active_record name matches up
533
623
  # with the current reflection's klass name.
534
- #
535
- # Note: klass will always be valid because when there's a NameError
536
- # from calling +klass+, +reflection+ will already be set to false.
537
624
  def valid_inverse_reflection?(reflection)
538
625
  reflection &&
539
- klass.name == reflection.active_record.name &&
626
+ foreign_key == reflection.foreign_key &&
627
+ klass <= reflection.active_record &&
540
628
  can_find_inverse_of_automatically?(reflection)
541
629
  end
542
630
 
@@ -544,9 +632,8 @@ module ActiveRecord
544
632
  # us from being able to guess the inverse automatically. First, the
545
633
  # <tt>inverse_of</tt> option cannot be set to false. Second, we must
546
634
  # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
547
- # Third, we must not have options such as <tt>:polymorphic</tt> or
548
- # <tt>:foreign_key</tt> which prevent us from correctly guessing the
549
- # inverse association.
635
+ # Third, we must not have options such as <tt>:foreign_key</tt>
636
+ # which prevent us from correctly guessing the inverse association.
550
637
  #
551
638
  # Anything with a scope can additionally ruin our attempt at finding an
552
639
  # inverse, so we exclude reflections with scopes.
@@ -576,56 +663,86 @@ module ActiveRecord
576
663
  def derive_join_table
577
664
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
578
665
  end
579
-
580
- def primary_key(klass)
581
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
582
- end
583
666
  end
584
667
 
585
668
  class HasManyReflection < AssociationReflection # :nodoc:
586
- def initialize(name, scope, options, active_record)
587
- super(name, scope, options, active_record)
588
- end
589
-
590
669
  def macro; :has_many; end
591
670
 
592
671
  def collection?; true; end
593
- end
594
672
 
595
- class HasOneReflection < AssociationReflection # :nodoc:
596
- def initialize(name, scope, options, active_record)
597
- super(name, scope, options, active_record)
673
+ def association_class
674
+ if options[:through]
675
+ Associations::HasManyThroughAssociation
676
+ else
677
+ Associations::HasManyAssociation
678
+ end
598
679
  end
680
+ end
599
681
 
682
+ class HasOneReflection < AssociationReflection # :nodoc:
600
683
  def macro; :has_one; end
601
684
 
602
685
  def has_one?; true; end
603
- end
604
686
 
605
- class BelongsToReflection < AssociationReflection # :nodoc:
606
- def initialize(name, scope, options, active_record)
607
- super(name, scope, options, active_record)
687
+ def association_class
688
+ if options[:through]
689
+ Associations::HasOneThroughAssociation
690
+ else
691
+ Associations::HasOneAssociation
692
+ end
608
693
  end
609
694
 
695
+ private
696
+ def calculate_constructable(macro, options)
697
+ !options[:through]
698
+ end
699
+ end
700
+
701
+ class BelongsToReflection < AssociationReflection # :nodoc:
610
702
  def macro; :belongs_to; end
611
703
 
612
704
  def belongs_to?; true; end
613
705
 
614
- def join_keys(assoc_klass)
615
- key = polymorphic? ? association_primary_key(assoc_klass) : association_primary_key
616
- JoinKeys.new(key, foreign_key)
706
+ def association_class
707
+ if polymorphic?
708
+ Associations::BelongsToPolymorphicAssociation
709
+ else
710
+ Associations::BelongsToAssociation
711
+ end
617
712
  end
618
713
 
619
- def join_id_for(owner) # :nodoc:
620
- owner[foreign_key]
714
+ # klass option is necessary to support loading polymorphic associations
715
+ def association_primary_key(klass = nil)
716
+ if primary_key = options[:primary_key]
717
+ @association_primary_key ||= -primary_key.to_s
718
+ else
719
+ primary_key(klass || self.klass)
720
+ end
621
721
  end
622
- end
623
722
 
624
- class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
625
- def initialize(name, scope, options, active_record)
626
- super
723
+ def join_primary_key(klass = nil)
724
+ polymorphic? ? association_primary_key(klass) : association_primary_key
725
+ end
726
+
727
+ def join_foreign_key
728
+ foreign_key
729
+ end
730
+
731
+ def join_foreign_type
732
+ foreign_type
627
733
  end
628
734
 
735
+ private
736
+ def can_find_inverse_of_automatically?(_)
737
+ !polymorphic? && super
738
+ end
739
+
740
+ def calculate_constructable(macro, options)
741
+ !polymorphic?
742
+ end
743
+ end
744
+
745
+ class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
629
746
  def macro; :has_and_belongs_to_many; end
630
747
 
631
748
  def collection?
@@ -633,19 +750,22 @@ module ActiveRecord
633
750
  end
634
751
  end
635
752
 
636
- # Holds all the meta-data about a :through association as it was specified
753
+ # Holds all the metadata about a :through association as it was specified
637
754
  # in the Active Record class.
638
755
  class ThroughReflection < AbstractReflection #:nodoc:
639
- attr_reader :delegate_reflection
640
- delegate :foreign_key, :foreign_type, :association_foreign_key,
641
- :active_record_primary_key, :type, :to => :source_reflection
756
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
757
+ :active_record_primary_key, :join_foreign_key, to: :source_reflection
642
758
 
643
759
  def initialize(delegate_reflection)
644
760
  @delegate_reflection = delegate_reflection
645
- @klass = delegate_reflection.options[:anonymous_class]
761
+ @klass = delegate_reflection.options[:anonymous_class]
646
762
  @source_reflection_name = delegate_reflection.options[:source]
647
763
  end
648
764
 
765
+ def through_reflection?
766
+ true
767
+ end
768
+
649
769
  def klass
650
770
  @klass ||= delegate_reflection.compute_class(class_name)
651
771
  end
@@ -704,74 +824,35 @@ module ActiveRecord
704
824
  # # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
705
825
  # <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
706
826
  #
707
- def chain
708
- @chain ||= begin
709
- a = source_reflection.chain
710
- b = through_reflection.chain
711
- chain = a + b
712
- chain[0] = self # Use self so we don't lose the information from :source_type
713
- chain
714
- end
827
+ def collect_join_chain
828
+ collect_join_reflections [self]
715
829
  end
716
830
 
717
- # Consider the following example:
718
- #
719
- # class Person
720
- # has_many :articles
721
- # has_many :comment_tags, through: :articles
722
- # end
723
- #
724
- # class Article
725
- # has_many :comments
726
- # has_many :comment_tags, through: :comments, source: :tags
727
- # end
728
- #
729
- # class Comment
730
- # has_many :tags
731
- # end
732
- #
733
- # There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags,
734
- # but only Comment.tags will be represented in the #chain. So this method creates an array
735
- # of scopes corresponding to the chain.
736
- def scope_chain
737
- @scope_chain ||= begin
738
- scope_chain = source_reflection.scope_chain.map(&:dup)
739
-
740
- # Add to it the scope from this reflection (if any)
741
- scope_chain.first << scope if scope
742
-
743
- through_scope_chain = through_reflection.scope_chain.map(&:dup)
744
-
745
- if options[:source_type]
746
- type = foreign_type
747
- source_type = options[:source_type]
748
- through_scope_chain.first << lambda { |object|
749
- where(type => source_type)
750
- }
751
- end
752
-
753
- # Recursively fill out the rest of the array from the through reflection
754
- scope_chain + through_scope_chain
755
- end
831
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
832
+ # SQL queries on associations.
833
+ def clear_association_scope_cache # :nodoc:
834
+ delegate_reflection.clear_association_scope_cache
835
+ source_reflection.clear_association_scope_cache
836
+ through_reflection.clear_association_scope_cache
756
837
  end
757
838
 
758
- def join_keys(assoc_klass)
759
- source_reflection.join_keys(assoc_klass)
839
+ def scopes
840
+ source_reflection.scopes + super
760
841
  end
761
842
 
762
- # The macro used by the source association
763
- def source_macro
764
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
765
- ActiveRecord::Base.source_macro is deprecated and will be removed
766
- without replacement.
767
- MSG
843
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
844
+ source_reflection.join_scopes(table, predicate_builder, klass) + super
845
+ end
768
846
 
769
- source_reflection.source_macro
847
+ def has_scope?
848
+ scope || options[:source_type] ||
849
+ source_reflection.has_scope? ||
850
+ through_reflection.has_scope?
770
851
  end
771
852
 
772
853
  # A through association is nested if there would be more than one join table
773
854
  def nested?
774
- chain.length > 2
855
+ source_reflection.through_reflection? || through_reflection.through_reflection?
775
856
  end
776
857
 
777
858
  # We want to use the klass from this reflection, rather than just delegate straight to
@@ -780,7 +861,15 @@ module ActiveRecord
780
861
  def association_primary_key(klass = nil)
781
862
  # Get the "actual" source reflection if the immediate source reflection has a
782
863
  # source reflection itself
783
- actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
864
+ if primary_key = actual_source_reflection.options[:primary_key]
865
+ @association_primary_key ||= -primary_key.to_s
866
+ else
867
+ primary_key(klass || self.klass)
868
+ end
869
+ end
870
+
871
+ def join_primary_key(klass = self.klass)
872
+ source_reflection.join_primary_key(klass)
784
873
  end
785
874
 
786
875
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
@@ -801,21 +890,19 @@ module ActiveRecord
801
890
  def source_reflection_name # :nodoc:
802
891
  return @source_reflection_name if @source_reflection_name
803
892
 
804
- names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq
893
+ names = [name.to_s.singularize, name].collect(&:to_sym).uniq
805
894
  names = names.find_all { |n|
806
895
  through_reflection.klass._reflect_on_association(n)
807
896
  }
808
897
 
809
898
  if names.length > 1
810
- example_options = options.dup
811
- example_options[:source] = source_reflection_names.first
812
- ActiveSupport::Deprecation.warn \
813
- "Ambiguous source reflection for through association. Please " \
814
- "specify a :source directive on your declaration like:\n" \
815
- "\n" \
816
- " class #{active_record.name} < ActiveRecord::Base\n" \
817
- " #{macro} :#{name}, #{example_options}\n" \
818
- " end"
899
+ raise AmbiguousSourceReflectionForThroughAssociation.new(
900
+ active_record.name,
901
+ macro,
902
+ name,
903
+ options,
904
+ source_reflection_names
905
+ )
819
906
  end
820
907
 
821
908
  @source_reflection_name = names.first
@@ -829,13 +916,9 @@ module ActiveRecord
829
916
  through_reflection.options
830
917
  end
831
918
 
832
- def join_id_for(owner) # :nodoc:
833
- source_reflection.join_id_for(owner)
834
- end
835
-
836
919
  def check_validity!
837
920
  if through_reflection.nil?
838
- raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
921
+ raise HasManyThroughAssociationNotFoundError.new(active_record, self)
839
922
  end
840
923
 
841
924
  if through_reflection.polymorphic?
@@ -862,22 +945,54 @@ module ActiveRecord
862
945
  raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
863
946
  end
864
947
 
948
+ if parent_reflection.nil?
949
+ reflections = active_record.reflections.keys.map(&:to_sym)
950
+
951
+ if reflections.index(through_reflection.name) > reflections.index(name)
952
+ raise HasManyThroughOrderError.new(active_record.name, self, through_reflection)
953
+ end
954
+ end
955
+
865
956
  check_validity_of_inverse!
866
957
  end
867
958
 
868
- protected
959
+ def constraints
960
+ scope_chain = source_reflection.constraints
961
+ scope_chain << scope if scope
962
+ scope_chain
963
+ end
964
+
965
+ def add_as_source(seed)
966
+ collect_join_reflections seed
967
+ end
968
+
969
+ def add_as_polymorphic_through(reflection, seed)
970
+ collect_join_reflections(seed + [PolymorphicReflection.new(self, reflection)])
971
+ end
972
+
973
+ def add_as_through(seed)
974
+ collect_join_reflections(seed + [self])
975
+ end
869
976
 
977
+ protected
870
978
  def actual_source_reflection # FIXME: this is a horrible name
871
- source_reflection.send(:actual_source_reflection)
979
+ source_reflection.actual_source_reflection
872
980
  end
873
981
 
874
- def primary_key(klass)
875
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
982
+ private
983
+ attr_reader :delegate_reflection
984
+
985
+ def collect_join_reflections(seed)
986
+ a = source_reflection.add_as_source seed
987
+ if options[:source_type]
988
+ through_reflection.add_as_polymorphic_through self, a
989
+ else
990
+ through_reflection.add_as_through a
991
+ end
876
992
  end
877
993
 
878
994
  def inverse_name; delegate_reflection.send(:inverse_name); end
879
995
 
880
- private
881
996
  def derive_class_name
882
997
  # get the class_name of the belongs_to association of the through reflection
883
998
  options[:source_type] || source_reflection.class_name
@@ -887,7 +1002,55 @@ module ActiveRecord
887
1002
  public_instance_methods
888
1003
 
889
1004
  delegate(*delegate_methods, to: :delegate_reflection)
1005
+ end
1006
+
1007
+ class PolymorphicReflection < AbstractReflection # :nodoc:
1008
+ delegate :klass, :scope, :plural_name, :type, :join_primary_key, :join_foreign_key,
1009
+ :name, :scope_for, to: :@reflection
1010
+
1011
+ def initialize(reflection, previous_reflection)
1012
+ @reflection = reflection
1013
+ @previous_reflection = previous_reflection
1014
+ end
1015
+
1016
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
1017
+ scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1018
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
1019
+ end
1020
+
1021
+ def constraints
1022
+ @reflection.constraints + [source_type_scope]
1023
+ end
1024
+
1025
+ private
1026
+ def source_type_scope
1027
+ type = @previous_reflection.foreign_type
1028
+ source_type = @previous_reflection.options[:source_type]
1029
+ lambda { |object| where(type => source_type) }
1030
+ end
1031
+ end
1032
+
1033
+ class RuntimeReflection < AbstractReflection # :nodoc:
1034
+ delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
1035
+
1036
+ def initialize(reflection, association)
1037
+ @reflection = reflection
1038
+ @association = association
1039
+ end
1040
+
1041
+ def klass
1042
+ @association.klass
1043
+ end
1044
+
1045
+ def aliased_table
1046
+ klass.arel_table
1047
+ end
1048
+
1049
+ def join_primary_key(klass = self.klass)
1050
+ @reflection.join_primary_key(klass)
1051
+ end
890
1052
 
1053
+ def all_includes; yield; end
891
1054
  end
892
1055
  end
893
1056
  end