activerecord 4.2.11.2 → 6.0.0

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

Potentially problematic release.


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

Files changed (372) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +613 -1638
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +13 -12
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record.rb +41 -22
  8. data/lib/active_record/aggregations.rb +267 -251
  9. data/lib/active_record/association_relation.rb +11 -6
  10. data/lib/active_record/associations.rb +1737 -1597
  11. data/lib/active_record/associations/alias_tracker.rb +29 -35
  12. data/lib/active_record/associations/association.rb +125 -58
  13. data/lib/active_record/associations/association_scope.rb +103 -132
  14. data/lib/active_record/associations/belongs_to_association.rb +65 -60
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -40
  17. data/lib/active_record/associations/builder/belongs_to.rb +69 -55
  18. data/lib/active_record/associations/builder/collection_association.rb +10 -33
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +52 -66
  20. data/lib/active_record/associations/builder/has_many.rb +8 -4
  21. data/lib/active_record/associations/builder/has_one.rb +46 -5
  22. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  23. data/lib/active_record/associations/collection_association.rb +131 -287
  24. data/lib/active_record/associations/collection_proxy.rb +241 -146
  25. data/lib/active_record/associations/foreign_association.rb +10 -1
  26. data/lib/active_record/associations/has_many_association.rb +34 -97
  27. data/lib/active_record/associations/has_many_through_association.rb +60 -87
  28. data/lib/active_record/associations/has_one_association.rb +61 -49
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +137 -167
  31. data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +90 -92
  35. data/lib/active_record/associations/preloader/association.rb +90 -123
  36. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  37. data/lib/active_record/associations/singular_association.rb +18 -39
  38. data/lib/active_record/associations/through_association.rb +38 -18
  39. data/lib/active_record/attribute_assignment.rb +56 -183
  40. data/lib/active_record/attribute_decorators.rb +39 -15
  41. data/lib/active_record/attribute_methods.rb +120 -135
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -8
  43. data/lib/active_record/attribute_methods/dirty.rb +174 -144
  44. data/lib/active_record/attribute_methods/primary_key.rb +91 -83
  45. data/lib/active_record/attribute_methods/query.rb +6 -5
  46. data/lib/active_record/attribute_methods/read.rb +20 -76
  47. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
  49. data/lib/active_record/attribute_methods/write.rb +32 -54
  50. data/lib/active_record/attributes.rb +214 -82
  51. data/lib/active_record/autosave_association.rb +91 -37
  52. data/lib/active_record/base.rb +57 -45
  53. data/lib/active_record/callbacks.rb +100 -74
  54. data/lib/active_record/coders/json.rb +3 -1
  55. data/lib/active_record/coders/yaml_column.rb +24 -12
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +796 -296
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -115
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -23
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +356 -227
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +664 -243
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -83
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +460 -204
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +510 -635
  69. data/lib/active_record/connection_adapters/column.rb +56 -43
  70. data/lib/active_record/connection_adapters/connection_specification.rb +174 -152
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +58 -180
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -114
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  96. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -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 +45 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  102. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  103. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +10 -5
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +470 -290
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +551 -356
  117. data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -345
  127. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  128. data/lib/active_record/connection_handling.rb +176 -41
  129. data/lib/active_record/core.rb +251 -231
  130. data/lib/active_record/counter_cache.rb +67 -49
  131. data/lib/active_record/database_configurations.rb +233 -0
  132. data/lib/active_record/database_configurations/database_config.rb +37 -0
  133. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  134. data/lib/active_record/database_configurations/url_config.rb +79 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +87 -105
  137. data/lib/active_record/enum.rb +163 -86
  138. data/lib/active_record/errors.rb +188 -53
  139. data/lib/active_record/explain.rb +23 -11
  140. data/lib/active_record/explain_registry.rb +4 -2
  141. data/lib/active_record/explain_subscriber.rb +10 -5
  142. data/lib/active_record/fixture_set/file.rb +35 -9
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +153 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  147. data/lib/active_record/fixtures.rb +228 -499
  148. data/lib/active_record/gem_version.rb +6 -4
  149. data/lib/active_record/inheritance.rb +158 -112
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +123 -29
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +21 -3
  154. data/lib/active_record/locale/en.yml +3 -2
  155. data/lib/active_record/locking/optimistic.rb +87 -96
  156. data/lib/active_record/locking/pessimistic.rb +18 -6
  157. data/lib/active_record/log_subscriber.rb +76 -33
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +621 -303
  162. data/lib/active_record/migration/command_recorder.rb +177 -90
  163. data/lib/active_record/migration/compatibility.rb +244 -0
  164. data/lib/active_record/migration/join_table.rb +8 -6
  165. data/lib/active_record/model_schema.rb +312 -112
  166. data/lib/active_record/nested_attributes.rb +264 -222
  167. data/lib/active_record/no_touching.rb +14 -1
  168. data/lib/active_record/null_relation.rb +24 -37
  169. data/lib/active_record/persistence.rb +557 -125
  170. data/lib/active_record/query_cache.rb +19 -23
  171. data/lib/active_record/querying.rb +43 -29
  172. data/lib/active_record/railtie.rb +143 -44
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +2 -0
  175. data/lib/active_record/railties/controller_runtime.rb +34 -33
  176. data/lib/active_record/railties/databases.rake +328 -185
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +428 -279
  179. data/lib/active_record/relation.rb +518 -341
  180. data/lib/active_record/relation/batches.rb +207 -55
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  182. data/lib/active_record/relation/calculations.rb +267 -253
  183. data/lib/active_record/relation/delegation.rb +70 -80
  184. data/lib/active_record/relation/finder_methods.rb +277 -241
  185. data/lib/active_record/relation/from_clause.rb +26 -0
  186. data/lib/active_record/relation/merger.rb +78 -87
  187. data/lib/active_record/relation/predicate_builder.rb +114 -119
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  195. data/lib/active_record/relation/query_attribute.rb +50 -0
  196. data/lib/active_record/relation/query_methods.rb +575 -394
  197. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  198. data/lib/active_record/relation/spawn_methods.rb +11 -13
  199. data/lib/active_record/relation/where_clause.rb +190 -0
  200. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  201. data/lib/active_record/result.rb +79 -42
  202. data/lib/active_record/runtime_registry.rb +6 -4
  203. data/lib/active_record/sanitization.rb +144 -121
  204. data/lib/active_record/schema.rb +21 -24
  205. data/lib/active_record/schema_dumper.rb +112 -93
  206. data/lib/active_record/schema_migration.rb +24 -17
  207. data/lib/active_record/scoping.rb +45 -26
  208. data/lib/active_record/scoping/default.rb +101 -85
  209. data/lib/active_record/scoping/named.rb +86 -33
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +5 -5
  212. data/lib/active_record/statement_cache.rb +73 -36
  213. data/lib/active_record/store.rb +127 -42
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +75 -0
  216. data/lib/active_record/tasks/database_tasks.rb +307 -100
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +55 -99
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -41
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +38 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +224 -0
  222. data/lib/active_record/timestamp.rb +86 -40
  223. data/lib/active_record/touch_later.rb +66 -0
  224. data/lib/active_record/transactions.rb +216 -150
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type.rb +78 -23
  227. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  228. data/lib/active_record/type/date.rb +4 -45
  229. data/lib/active_record/type/date_time.rb +4 -49
  230. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  231. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  232. data/lib/active_record/type/internal/timezone.rb +17 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +24 -15
  235. data/lib/active_record/type/text.rb +2 -2
  236. data/lib/active_record/type/time.rb +11 -16
  237. data/lib/active_record/type/type_map.rb +15 -17
  238. data/lib/active_record/type/unsigned_integer.rb +9 -7
  239. data/lib/active_record/type_caster.rb +9 -0
  240. data/lib/active_record/type_caster/connection.rb +34 -0
  241. data/lib/active_record/type_caster/map.rb +20 -0
  242. data/lib/active_record/validations.rb +39 -35
  243. data/lib/active_record/validations/absence.rb +25 -0
  244. data/lib/active_record/validations/associated.rb +13 -4
  245. data/lib/active_record/validations/length.rb +26 -0
  246. data/lib/active_record/validations/presence.rb +14 -13
  247. data/lib/active_record/validations/uniqueness.rb +42 -55
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/arel.rb +51 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +257 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +204 -0
  317. data/lib/arel/visitors/dot.rb +297 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +157 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +159 -0
  323. data/lib/arel/visitors/oracle12.rb +66 -0
  324. data/lib/arel/visitors/postgresql.rb +110 -0
  325. data/lib/arel/visitors/sqlite.rb +39 -0
  326. data/lib/arel/visitors/to_sql.rb +889 -0
  327. data/lib/arel/visitors/visitor.rb +46 -0
  328. data/lib/arel/visitors/where_sql.rb +23 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +7 -5
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration.rb +31 -1
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +42 -37
  335. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  336. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -2
  337. data/lib/rails/generators/active_record/model/model_generator.rb +19 -22
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  340. metadata +164 -59
  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_set.rb +0 -81
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  352. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  353. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  354. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  355. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  356. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  359. data/lib/active_record/type/big_integer.rb +0 -13
  360. data/lib/active_record/type/binary.rb +0 -50
  361. data/lib/active_record/type/boolean.rb +0 -31
  362. data/lib/active_record/type/decimal.rb +0 -64
  363. data/lib/active_record/type/decorator.rb +0 -14
  364. data/lib/active_record/type/float.rb +0 -19
  365. data/lib/active_record/type/integer.rb +0 -59
  366. data/lib/active_record/type/mutable.rb +0 -16
  367. data/lib/active_record/type/numeric.rb +0 -36
  368. data/lib/active_record/type/string.rb +0 -40
  369. data/lib/active_record/type/time_value.rb +0 -38
  370. data/lib/active_record/type/value.rb +0 -110
  371. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  372. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,22 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ReadonlyAttributes
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  included do
6
- class_attribute :_attr_readonly, instance_accessor: false
7
- self._attr_readonly = []
8
+ class_attribute :_attr_readonly, instance_accessor: false, default: []
8
9
  end
9
10
 
10
11
  module ClassMethods
11
12
  # Attributes listed as readonly will be used to create a new record but update operations will
12
13
  # ignore these fields.
13
14
  def attr_readonly(*attributes)
14
- self._attr_readonly = Set.new(attributes.map { |a| a.to_s }) + (self._attr_readonly || [])
15
+ self._attr_readonly = Set.new(attributes.map(&:to_s)) + (_attr_readonly || [])
15
16
  end
16
17
 
17
18
  # Returns an array of all the attributes that have been specified as readonly.
18
19
  def readonly_attributes
19
- self._attr_readonly
20
+ _attr_readonly
20
21
  end
21
22
  end
22
23
  end
@@ -1,5 +1,7 @@
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"
4
+ require "concurrent/map"
3
5
 
4
6
  module ActiveRecord
5
7
  # = Active Record Reflection
@@ -7,42 +9,46 @@ module ActiveRecord
7
9
  extend ActiveSupport::Concern
8
10
 
9
11
  included do
10
- class_attribute :_reflections, instance_writer: false
11
- class_attribute :aggregate_reflections, instance_writer: false
12
- self._reflections = {}
13
- self.aggregate_reflections = {}
12
+ class_attribute :_reflections, instance_writer: false, default: {}
13
+ class_attribute :aggregate_reflections, instance_writer: false, default: {}
14
14
  end
15
15
 
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
16
+ class << self
17
+ def create(macro, name, scope, options, ar)
18
+ reflection = reflection_class_for(macro).new(name, scope, options, ar)
19
+ options[:through] ? ThroughReflection.new(reflection) : reflection
20
+ end
33
21
 
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
22
+ def add_reflection(ar, name, reflection)
23
+ ar.clear_reflections_cache
24
+ name = -name.to_s
25
+ ar._reflections = ar._reflections.except(name).merge!(name => reflection)
26
+ end
27
+
28
+ def add_aggregate_reflection(ar, name, reflection)
29
+ ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
30
+ end
38
31
 
39
- def self.add_aggregate_reflection(ar, name, reflection)
40
- ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
32
+ private
33
+ def reflection_class_for(macro)
34
+ case macro
35
+ when :composed_of
36
+ AggregateReflection
37
+ when :has_many
38
+ HasManyReflection
39
+ when :has_one
40
+ HasOneReflection
41
+ when :belongs_to
42
+ BelongsToReflection
43
+ else
44
+ raise "Unsupported Macro: #{macro}"
45
+ end
46
+ end
41
47
  end
42
48
 
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
49
+ # \Reflection enables the ability to examine the associations and aggregations of
50
+ # Active Record classes and objects. This information, for example,
51
+ # can be used in a form builder that takes an Active Record object
46
52
  # and creates input fields for all of the attributes depending on their type
47
53
  # and displays the associations to other objects.
48
54
  #
@@ -62,20 +68,20 @@ module ActiveRecord
62
68
  aggregate_reflections[aggregation.to_s]
63
69
  end
64
70
 
65
- # Returns a Hash of name of the reflection as the key and a AssociationReflection as the value.
71
+ # Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
66
72
  #
67
73
  # Account.reflections # => {"balance" => AggregateReflection}
68
74
  #
69
- # @api public
70
75
  def reflections
71
76
  @__reflections ||= begin
72
77
  ref = {}
73
78
 
74
79
  _reflections.each do |name, reflection|
75
- parent_name, parent_reflection = reflection.parent_reflection
80
+ parent_reflection = reflection.parent_reflection
76
81
 
77
- if parent_name
78
- ref[parent_name] = parent_reflection
82
+ if parent_reflection
83
+ parent_name = parent_reflection.name
84
+ ref[parent_name.to_s] = parent_reflection
79
85
  else
80
86
  ref[name] = reflection
81
87
  end
@@ -95,10 +101,10 @@ module ActiveRecord
95
101
  # Account.reflect_on_all_associations # returns an array of all associations
96
102
  # Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
97
103
  #
98
- # @api public
99
104
  def reflect_on_all_associations(macro = nil)
100
105
  association_reflections = reflections.values
101
- macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
106
+ association_reflections.select! { |reflection| reflection.macro == macro } if macro
107
+ association_reflections
102
108
  end
103
109
 
104
110
  # Returns the AssociationReflection object for the +association+ (use the symbol).
@@ -106,31 +112,42 @@ module ActiveRecord
106
112
  # Account.reflect_on_association(:owner) # returns the owner AssociationReflection
107
113
  # Invoice.reflect_on_association(:line_items).macro # returns :has_many
108
114
  #
109
- # @api public
110
115
  def reflect_on_association(association)
111
116
  reflections[association.to_s]
112
117
  end
113
118
 
114
- # @api private
115
119
  def _reflect_on_association(association) #:nodoc:
116
120
  _reflections[association.to_s]
117
121
  end
118
122
 
119
123
  # Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
120
- #
121
- # @api public
122
124
  def reflect_on_all_autosave_associations
123
125
  reflections.values.select { |reflection| reflection.options[:autosave] }
124
126
  end
125
127
 
126
- def clear_reflections_cache #:nodoc:
128
+ def clear_reflections_cache # :nodoc:
127
129
  @__reflections = nil
128
130
  end
129
131
  end
130
132
 
131
- # Holds all the methods that are shared between MacroReflection, AssociationReflection
132
- # and ThroughReflection
133
+ # Holds all the methods that are shared between MacroReflection and ThroughReflection.
134
+ #
135
+ # AbstractReflection
136
+ # MacroReflection
137
+ # AggregateReflection
138
+ # AssociationReflection
139
+ # HasManyReflection
140
+ # HasOneReflection
141
+ # BelongsToReflection
142
+ # HasAndBelongsToManyReflection
143
+ # ThroughReflection
144
+ # PolymorphicReflection
145
+ # RuntimeReflection
133
146
  class AbstractReflection # :nodoc:
147
+ def through_reflection?
148
+ false
149
+ end
150
+
134
151
  def table_name
135
152
  klass.table_name
136
153
  end
@@ -141,14 +158,6 @@ module ActiveRecord
141
158
  klass.new(attributes, &block)
142
159
  end
143
160
 
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
161
  # Returns the class name for the macro.
153
162
  #
154
163
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
@@ -159,17 +168,64 @@ module ActiveRecord
159
168
 
160
169
  JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
161
170
 
162
- def join_keys(assoc_klass)
163
- JoinKeys.new(foreign_key, active_record_primary_key)
171
+ def join_keys
172
+ @join_keys ||= get_join_keys(klass)
173
+ end
174
+
175
+ # Returns a list of scopes that should be applied for this Reflection
176
+ # object when querying the database.
177
+ def scopes
178
+ scope ? [scope] : []
179
+ end
180
+
181
+ def join_scope(table, foreign_table, foreign_klass)
182
+ predicate_builder = predicate_builder(table)
183
+ scope_chain_items = join_scopes(table, predicate_builder)
184
+ klass_scope = klass_join_scope(table, predicate_builder)
185
+
186
+ key = join_keys.key
187
+ foreign_key = join_keys.foreign_key
188
+
189
+ klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
190
+
191
+ if type
192
+ klass_scope.where!(type => foreign_klass.polymorphic_name)
193
+ end
194
+
195
+ if klass.finder_needs_type_condition?
196
+ klass_scope.where!(klass.send(:type_condition, table))
197
+ end
198
+
199
+ scope_chain_items.inject(klass_scope, &:merge!)
200
+ end
201
+
202
+ def join_scopes(table, predicate_builder) # :nodoc:
203
+ if scope
204
+ [scope_for(build_scope(table, predicate_builder))]
205
+ else
206
+ []
207
+ end
208
+ end
209
+
210
+ def klass_join_scope(table, predicate_builder) # :nodoc:
211
+ relation = build_scope(table, predicate_builder)
212
+ klass.scope_for_association(relation)
164
213
  end
165
214
 
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
215
+ def constraints
216
+ chain.flat_map(&:scopes)
217
+ end
171
218
 
172
- macro
219
+ def counter_cache_column
220
+ if belongs_to?
221
+ if options[:counter_cache] == true
222
+ "#{active_record.name.demodulize.underscore.pluralize}_count"
223
+ elsif options[:counter_cache]
224
+ options[:counter_cache].to_s
225
+ end
226
+ else
227
+ options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
228
+ end
173
229
  end
174
230
 
175
231
  def inverse_of
@@ -185,17 +241,88 @@ module ActiveRecord
185
241
  end
186
242
  end
187
243
  end
244
+
245
+ # This shit is nasty. We need to avoid the following situation:
246
+ #
247
+ # * An associated record is deleted via record.destroy
248
+ # * Hence the callbacks run, and they find a belongs_to on the record with a
249
+ # :counter_cache options which points back at our owner. So they update the
250
+ # counter cache.
251
+ # * In which case, we must make sure to *not* update the counter cache, or else
252
+ # it will be decremented twice.
253
+ #
254
+ # Hence this method.
255
+ def inverse_which_updates_counter_cache
256
+ return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
257
+ @inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
258
+ inverse.counter_cache_column == counter_cache_column
259
+ end
260
+ end
261
+ alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
262
+
263
+ def inverse_updates_counter_in_memory?
264
+ inverse_of && inverse_which_updates_counter_cache == inverse_of
265
+ end
266
+
267
+ # Returns whether a counter cache should be used for this association.
268
+ #
269
+ # The counter_cache option must be given on either the owner or inverse
270
+ # association, and the column must be present on the owner.
271
+ def has_cached_counter?
272
+ options[:counter_cache] ||
273
+ inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
274
+ !!active_record.columns_hash[counter_cache_column]
275
+ end
276
+
277
+ def counter_must_be_updated_by_has_many?
278
+ !inverse_updates_counter_in_memory? && has_cached_counter?
279
+ end
280
+
281
+ def alias_candidate(name)
282
+ "#{plural_name}_#{name}"
283
+ end
284
+
285
+ def chain
286
+ collect_join_chain
287
+ end
288
+
289
+ def get_join_keys(association_klass)
290
+ JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
291
+ end
292
+
293
+ def build_scope(table, predicate_builder = predicate_builder(table))
294
+ Relation.create(
295
+ klass,
296
+ table: table,
297
+ predicate_builder: predicate_builder
298
+ )
299
+ end
300
+
301
+ def join_primary_key(*)
302
+ foreign_key
303
+ end
304
+
305
+ def join_foreign_key
306
+ active_record_primary_key
307
+ end
308
+
309
+ protected
310
+ def actual_source_reflection # FIXME: this is a horrible name
311
+ self
312
+ end
313
+
314
+ private
315
+ def predicate_builder(table)
316
+ PredicateBuilder.new(TableMetadata.new(klass, table))
317
+ end
318
+
319
+ def primary_key(klass)
320
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
321
+ end
188
322
  end
323
+
189
324
  # Base class for AggregateReflection and AssociationReflection. Objects of
190
325
  # 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
326
  class MacroReflection < AbstractReflection
200
327
  # Returns the name of the macro.
201
328
  #
@@ -226,9 +353,8 @@ module ActiveRecord
226
353
  end
227
354
 
228
355
  def autosave=(autosave)
229
- @automatic_inverse_of = false
230
356
  @options[:autosave] = autosave
231
- _, parent_reflection = self.parent_reflection
357
+ parent_reflection = self.parent_reflection
232
358
  if parent_reflection
233
359
  parent_reflection.autosave = autosave
234
360
  end
@@ -238,6 +364,17 @@ module ActiveRecord
238
364
  #
239
365
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
240
366
  # <tt>has_many :clients</tt> returns the Client class
367
+ #
368
+ # class Company < ActiveRecord::Base
369
+ # has_many :clients
370
+ # end
371
+ #
372
+ # Company.reflect_on_association(:clients).klass
373
+ # # => Client
374
+ #
375
+ # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
376
+ # a new association object. Use +build_association+ or +create_association+
377
+ # instead. This allows plugins to hook into association object creation.
241
378
  def klass
242
379
  @klass ||= compute_class(class_name)
243
380
  end
@@ -256,14 +393,17 @@ module ActiveRecord
256
393
  active_record == other_aggregation.active_record
257
394
  end
258
395
 
396
+ def scope_for(relation, owner = nil)
397
+ relation.instance_exec(owner, &scope) || relation
398
+ end
399
+
259
400
  private
260
401
  def derive_class_name
261
402
  name.to_s.camelize
262
403
  end
263
404
  end
264
405
 
265
-
266
- # Holds all the meta-data about an aggregation as it was specified in the
406
+ # Holds all the metadata about an aggregation as it was specified in the
267
407
  # Active Record class.
268
408
  class AggregateReflection < MacroReflection #:nodoc:
269
409
  def mapping
@@ -272,50 +412,37 @@ module ActiveRecord
272
412
  end
273
413
  end
274
414
 
275
- # Holds all the meta-data about an association as it was specified in the
415
+ # Holds all the metadata about an association as it was specified in the
276
416
  # Active Record class.
277
417
  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
418
  def compute_class(name)
419
+ if polymorphic?
420
+ raise ArgumentError, "Polymorphic associations do not support computing the class."
421
+ end
295
422
  active_record.send(:compute_type, name)
296
423
  end
297
424
 
298
425
  attr_reader :type, :foreign_type
299
- attr_accessor :parent_reflection # [:name, Reflection]
426
+ attr_accessor :parent_reflection # Reflection
300
427
 
301
428
  def initialize(name, scope, options, active_record)
302
429
  super
303
- @automatic_inverse_of = nil
304
430
  @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
305
- @foreign_type = options[:foreign_type] || "#{name}_type"
431
+ @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
306
432
  @constructable = calculate_constructable(macro, options)
307
- @association_scope_cache = {}
308
- @scope_lock = Mutex.new
433
+ @association_scope_cache = Concurrent::Map.new
434
+
435
+ if options[:class_name] && options[:class_name].class == Class
436
+ raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
437
+ end
309
438
  end
310
439
 
311
- def association_scope_cache(conn, owner)
440
+ def association_scope_cache(conn, owner, &block)
312
441
  key = conn.prepared_statements
313
442
  if polymorphic?
314
443
  key = [key, owner._read_attribute(@foreign_type)]
315
444
  end
316
- @association_scope_cache[key] ||= @scope_lock.synchronize {
317
- @association_scope_cache[key] ||= yield
318
- }
445
+ @association_scope_cache.compute_if_absent(key) { StatementCache.create(conn, &block) }
319
446
  end
320
447
 
321
448
  def constructable? # :nodoc:
@@ -343,14 +470,6 @@ module ActiveRecord
343
470
  @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
344
471
  end
345
472
 
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
352
- end
353
-
354
473
  def check_validity!
355
474
  check_validity_of_inverse!
356
475
  end
@@ -358,21 +477,18 @@ module ActiveRecord
358
477
  def check_preloadable!
359
478
  return unless scope
360
479
 
361
- if scope.arity > 0
362
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
480
+ unless scope.arity == 0
481
+ raise ArgumentError, <<-MSG.squish
363
482
  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.
483
+ block takes an argument). Preloading instance dependent scopes is
484
+ not supported.
369
485
  MSG
370
486
  end
371
487
  end
372
488
  alias :check_eager_loadable! :check_preloadable!
373
489
 
374
490
  def join_id_for(owner) # :nodoc:
375
- owner[active_record_primary_key]
491
+ owner[join_foreign_key]
376
492
  end
377
493
 
378
494
  def through_reflection
@@ -385,18 +501,22 @@ module ActiveRecord
385
501
 
386
502
  # A chain of reflections from this one back to the owner. For more see the explanation in
387
503
  # ThroughReflection.
388
- def chain
504
+ def collect_join_chain
389
505
  [self]
390
506
  end
391
507
 
508
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
509
+ # SQL queries on associations.
510
+ def clear_association_scope_cache # :nodoc:
511
+ @association_scope_cache.clear
512
+ end
513
+
392
514
  def nested?
393
515
  false
394
516
  end
395
517
 
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]] : [[]]
518
+ def has_scope?
519
+ scope
400
520
  end
401
521
 
402
522
  def has_inverse?
@@ -444,69 +564,49 @@ module ActiveRecord
444
564
  # Returns +true+ if +self+ is a +has_one+ reflection.
445
565
  def has_one?; false; end
446
566
 
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
567
+ def association_class; raise NotImplementedError; end
469
568
 
470
569
  def polymorphic?
471
570
  options[:polymorphic]
472
571
  end
473
572
 
474
573
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
475
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
574
+ INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
476
575
 
477
- protected
576
+ def add_as_source(seed)
577
+ seed
578
+ end
478
579
 
479
- def actual_source_reflection # FIXME: this is a horrible name
480
- self
481
- end
580
+ def add_as_polymorphic_through(reflection, seed)
581
+ seed + [PolymorphicReflection.new(self, reflection)]
582
+ end
583
+
584
+ def add_as_through(seed)
585
+ seed + [self]
586
+ end
587
+
588
+ def extensions
589
+ Array(options[:extend])
590
+ end
482
591
 
483
592
  private
484
593
 
485
594
  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
595
+ true
494
596
  end
495
597
 
496
598
  # Attempts to find the inverse association name automatically.
497
599
  # If it cannot find a suitable inverse association name, it returns
498
- # nil.
600
+ # +nil+.
499
601
  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
602
+ unless defined?(@inverse_name)
603
+ @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
506
604
  end
605
+
606
+ @inverse_name
507
607
  end
508
608
 
509
- # returns either nil or the inverse association name that it finds.
609
+ # returns either +nil+ or the inverse association name that it finds.
510
610
  def automatic_inverse_of
511
611
  if can_find_inverse_of_automatically?(self)
512
612
  inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
@@ -523,20 +623,15 @@ module ActiveRecord
523
623
  return inverse_name
524
624
  end
525
625
  end
526
-
527
- false
528
626
  end
529
627
 
530
628
  # Checks if the inverse reflection that is returned from the
531
629
  # +automatic_inverse_of+ method is a valid reflection. We must
532
630
  # make sure that the reflection's active_record name matches up
533
631
  # 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
632
  def valid_inverse_reflection?(reflection)
538
633
  reflection &&
539
- klass.name == reflection.active_record.name &&
634
+ klass <= reflection.active_record &&
540
635
  can_find_inverse_of_automatically?(reflection)
541
636
  end
542
637
 
@@ -544,9 +639,8 @@ module ActiveRecord
544
639
  # us from being able to guess the inverse automatically. First, the
545
640
  # <tt>inverse_of</tt> option cannot be set to false. Second, we must
546
641
  # 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.
642
+ # Third, we must not have options such as <tt>:foreign_key</tt>
643
+ # which prevent us from correctly guessing the inverse association.
550
644
  #
551
645
  # Anything with a scope can additionally ruin our attempt at finding an
552
646
  # inverse, so we exclude reflections with scopes.
@@ -576,56 +670,78 @@ module ActiveRecord
576
670
  def derive_join_table
577
671
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
578
672
  end
579
-
580
- def primary_key(klass)
581
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
582
- end
583
673
  end
584
674
 
585
675
  class HasManyReflection < AssociationReflection # :nodoc:
586
- def initialize(name, scope, options, active_record)
587
- super(name, scope, options, active_record)
588
- end
589
-
590
676
  def macro; :has_many; end
591
677
 
592
678
  def collection?; true; end
593
- end
594
679
 
595
- class HasOneReflection < AssociationReflection # :nodoc:
596
- def initialize(name, scope, options, active_record)
597
- super(name, scope, options, active_record)
680
+ def association_class
681
+ if options[:through]
682
+ Associations::HasManyThroughAssociation
683
+ else
684
+ Associations::HasManyAssociation
685
+ end
686
+ end
687
+
688
+ def association_primary_key(klass = nil)
689
+ primary_key(klass || self.klass)
598
690
  end
691
+ end
599
692
 
693
+ class HasOneReflection < AssociationReflection # :nodoc:
600
694
  def macro; :has_one; end
601
695
 
602
696
  def has_one?; true; end
603
- end
604
697
 
605
- class BelongsToReflection < AssociationReflection # :nodoc:
606
- def initialize(name, scope, options, active_record)
607
- super(name, scope, options, active_record)
698
+ def association_class
699
+ if options[:through]
700
+ Associations::HasOneThroughAssociation
701
+ else
702
+ Associations::HasOneAssociation
703
+ end
608
704
  end
609
705
 
706
+ private
707
+
708
+ def calculate_constructable(macro, options)
709
+ !options[:through]
710
+ end
711
+ end
712
+
713
+ class BelongsToReflection < AssociationReflection # :nodoc:
610
714
  def macro; :belongs_to; end
611
715
 
612
716
  def belongs_to?; true; end
613
717
 
614
- def join_keys(assoc_klass)
615
- key = polymorphic? ? association_primary_key(assoc_klass) : association_primary_key
616
- JoinKeys.new(key, foreign_key)
718
+ def association_class
719
+ if polymorphic?
720
+ Associations::BelongsToPolymorphicAssociation
721
+ else
722
+ Associations::BelongsToAssociation
723
+ end
724
+ end
725
+
726
+ def join_primary_key(klass = nil)
727
+ polymorphic? ? association_primary_key(klass) : association_primary_key
617
728
  end
618
729
 
619
- def join_id_for(owner) # :nodoc:
620
- owner[foreign_key]
730
+ def join_foreign_key
731
+ foreign_key
621
732
  end
733
+
734
+ private
735
+ def can_find_inverse_of_automatically?(_)
736
+ !polymorphic? && super
737
+ end
738
+
739
+ def calculate_constructable(macro, options)
740
+ !polymorphic?
741
+ end
622
742
  end
623
743
 
624
744
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
625
- def initialize(name, scope, options, active_record)
626
- super
627
- end
628
-
629
745
  def macro; :has_and_belongs_to_many; end
630
746
 
631
747
  def collection?
@@ -633,19 +749,22 @@ module ActiveRecord
633
749
  end
634
750
  end
635
751
 
636
- # Holds all the meta-data about a :through association as it was specified
752
+ # Holds all the metadata about a :through association as it was specified
637
753
  # in the Active Record class.
638
754
  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
755
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
756
+ :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
642
757
 
643
758
  def initialize(delegate_reflection)
644
759
  @delegate_reflection = delegate_reflection
645
- @klass = delegate_reflection.options[:anonymous_class]
760
+ @klass = delegate_reflection.options[:anonymous_class]
646
761
  @source_reflection_name = delegate_reflection.options[:source]
647
762
  end
648
763
 
764
+ def through_reflection?
765
+ true
766
+ end
767
+
649
768
  def klass
650
769
  @klass ||= delegate_reflection.compute_class(class_name)
651
770
  end
@@ -704,74 +823,35 @@ module ActiveRecord
704
823
  # # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
705
824
  # <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
706
825
  #
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
826
+ def collect_join_chain
827
+ collect_join_reflections [self]
715
828
  end
716
829
 
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
830
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
831
+ # SQL queries on associations.
832
+ def clear_association_scope_cache # :nodoc:
833
+ delegate_reflection.clear_association_scope_cache
834
+ source_reflection.clear_association_scope_cache
835
+ through_reflection.clear_association_scope_cache
756
836
  end
757
837
 
758
- def join_keys(assoc_klass)
759
- source_reflection.join_keys(assoc_klass)
838
+ def scopes
839
+ source_reflection.scopes + super
760
840
  end
761
841
 
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
842
+ def join_scopes(table, predicate_builder) # :nodoc:
843
+ source_reflection.join_scopes(table, predicate_builder) + super
844
+ end
768
845
 
769
- source_reflection.source_macro
846
+ def has_scope?
847
+ scope || options[:source_type] ||
848
+ source_reflection.has_scope? ||
849
+ through_reflection.has_scope?
770
850
  end
771
851
 
772
852
  # A through association is nested if there would be more than one join table
773
853
  def nested?
774
- chain.length > 2
854
+ source_reflection.through_reflection? || through_reflection.through_reflection?
775
855
  end
776
856
 
777
857
  # We want to use the klass from this reflection, rather than just delegate straight to
@@ -801,21 +881,19 @@ module ActiveRecord
801
881
  def source_reflection_name # :nodoc:
802
882
  return @source_reflection_name if @source_reflection_name
803
883
 
804
- names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq
884
+ names = [name.to_s.singularize, name].collect(&:to_sym).uniq
805
885
  names = names.find_all { |n|
806
886
  through_reflection.klass._reflect_on_association(n)
807
887
  }
808
888
 
809
889
  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"
890
+ raise AmbiguousSourceReflectionForThroughAssociation.new(
891
+ active_record.name,
892
+ macro,
893
+ name,
894
+ options,
895
+ source_reflection_names
896
+ )
819
897
  end
820
898
 
821
899
  @source_reflection_name = names.first
@@ -829,10 +907,6 @@ module ActiveRecord
829
907
  through_reflection.options
830
908
  end
831
909
 
832
- def join_id_for(owner) # :nodoc:
833
- source_reflection.join_id_for(owner)
834
- end
835
-
836
910
  def check_validity!
837
911
  if through_reflection.nil?
838
912
  raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
@@ -862,22 +936,54 @@ module ActiveRecord
862
936
  raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
863
937
  end
864
938
 
939
+ if parent_reflection.nil?
940
+ reflections = active_record.reflections.keys.map(&:to_sym)
941
+
942
+ if reflections.index(through_reflection.name) > reflections.index(name)
943
+ raise HasManyThroughOrderError.new(active_record.name, self, through_reflection)
944
+ end
945
+ end
946
+
865
947
  check_validity_of_inverse!
866
948
  end
867
949
 
868
- protected
950
+ def constraints
951
+ scope_chain = source_reflection.constraints
952
+ scope_chain << scope if scope
953
+ scope_chain
954
+ end
955
+
956
+ def add_as_source(seed)
957
+ collect_join_reflections seed
958
+ end
959
+
960
+ def add_as_polymorphic_through(reflection, seed)
961
+ collect_join_reflections(seed + [PolymorphicReflection.new(self, reflection)])
962
+ end
869
963
 
964
+ def add_as_through(seed)
965
+ collect_join_reflections(seed + [self])
966
+ end
967
+
968
+ protected
870
969
  def actual_source_reflection # FIXME: this is a horrible name
871
- source_reflection.send(:actual_source_reflection)
970
+ source_reflection.actual_source_reflection
872
971
  end
873
972
 
874
- def primary_key(klass)
875
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
973
+ private
974
+ attr_reader :delegate_reflection
975
+
976
+ def collect_join_reflections(seed)
977
+ a = source_reflection.add_as_source seed
978
+ if options[:source_type]
979
+ through_reflection.add_as_polymorphic_through self, a
980
+ else
981
+ through_reflection.add_as_through a
982
+ end
876
983
  end
877
984
 
878
985
  def inverse_name; delegate_reflection.send(:inverse_name); end
879
986
 
880
- private
881
987
  def derive_class_name
882
988
  # get the class_name of the belongs_to association of the through reflection
883
989
  options[:source_type] || source_reflection.class_name
@@ -887,7 +993,50 @@ module ActiveRecord
887
993
  public_instance_methods
888
994
 
889
995
  delegate(*delegate_methods, to: :delegate_reflection)
996
+ end
997
+
998
+ class PolymorphicReflection < AbstractReflection # :nodoc:
999
+ delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
1000
+
1001
+ def initialize(reflection, previous_reflection)
1002
+ @reflection = reflection
1003
+ @previous_reflection = previous_reflection
1004
+ end
1005
+
1006
+ def join_scopes(table, predicate_builder) # :nodoc:
1007
+ scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1008
+ scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
1009
+ end
1010
+
1011
+ def constraints
1012
+ @reflection.constraints + [source_type_scope]
1013
+ end
1014
+
1015
+ private
1016
+ def source_type_scope
1017
+ type = @previous_reflection.foreign_type
1018
+ source_type = @previous_reflection.options[:source_type]
1019
+ lambda { |object| where(type => source_type) }
1020
+ end
1021
+ end
1022
+
1023
+ class RuntimeReflection < AbstractReflection # :nodoc:
1024
+ delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
1025
+
1026
+ def initialize(reflection, association)
1027
+ @reflection = reflection
1028
+ @association = association
1029
+ end
1030
+
1031
+ def klass
1032
+ @association.klass
1033
+ end
1034
+
1035
+ def aliased_table
1036
+ @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
1037
+ end
890
1038
 
1039
+ def all_includes; yield; end
891
1040
  end
892
1041
  end
893
1042
  end