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