activerecord 4.2.11.1 → 6.0.3

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 (373) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +711 -1547
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +14 -13
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/advisory_lock_base.rb +18 -0
  8. data/lib/active_record/aggregations.rb +266 -251
  9. data/lib/active_record/association_relation.rb +20 -13
  10. data/lib/active_record/associations/alias_tracker.rb +29 -36
  11. data/lib/active_record/associations/association.rb +128 -57
  12. data/lib/active_record/associations/association_scope.rb +103 -132
  13. data/lib/active_record/associations/belongs_to_association.rb +65 -60
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  15. data/lib/active_record/associations/builder/association.rb +27 -40
  16. data/lib/active_record/associations/builder/belongs_to.rb +69 -55
  17. data/lib/active_record/associations/builder/collection_association.rb +10 -33
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -66
  19. data/lib/active_record/associations/builder/has_many.rb +8 -4
  20. data/lib/active_record/associations/builder/has_one.rb +46 -5
  21. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  22. data/lib/active_record/associations/collection_association.rb +136 -288
  23. data/lib/active_record/associations/collection_proxy.rb +241 -147
  24. data/lib/active_record/associations/foreign_association.rb +10 -1
  25. data/lib/active_record/associations/has_many_association.rb +34 -98
  26. data/lib/active_record/associations/has_many_through_association.rb +60 -87
  27. data/lib/active_record/associations/has_one_association.rb +61 -49
  28. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  29. data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
  30. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  31. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  32. data/lib/active_record/associations/join_dependency.rb +149 -166
  33. data/lib/active_record/associations/preloader/association.rb +90 -123
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  35. data/lib/active_record/associations/preloader.rb +90 -93
  36. data/lib/active_record/associations/singular_association.rb +18 -39
  37. data/lib/active_record/associations/through_association.rb +38 -18
  38. data/lib/active_record/associations.rb +1737 -1597
  39. data/lib/active_record/attribute_assignment.rb +57 -185
  40. data/lib/active_record/attribute_decorators.rb +39 -17
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  42. data/lib/active_record/attribute_methods/dirty.rb +174 -144
  43. data/lib/active_record/attribute_methods/primary_key.rb +90 -84
  44. data/lib/active_record/attribute_methods/query.rb +6 -5
  45. data/lib/active_record/attribute_methods/read.rb +20 -77
  46. data/lib/active_record/attribute_methods/serialization.rb +40 -21
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +57 -37
  48. data/lib/active_record/attribute_methods/write.rb +32 -55
  49. data/lib/active_record/attribute_methods.rb +120 -135
  50. data/lib/active_record/attributes.rb +213 -82
  51. data/lib/active_record/autosave_association.rb +97 -41
  52. data/lib/active_record/base.rb +57 -45
  53. data/lib/active_record/callbacks.rb +101 -76
  54. data/lib/active_record/coders/json.rb +3 -1
  55. data/lib/active_record/coders/yaml_column.rb +23 -12
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +804 -297
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +240 -115
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -24
  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 -47
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +371 -242
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +694 -256
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +190 -83
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +473 -202
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +507 -639
  69. data/lib/active_record/connection_adapters/column.rb +56 -43
  70. data/lib/active_record/connection_adapters/connection_specification.rb +174 -153
  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 +196 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +71 -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 -181
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -114
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -58
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +51 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -5
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  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 +49 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -296
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -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 +119 -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 +102 -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 +299 -349
  127. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  128. data/lib/active_record/connection_handling.rb +167 -41
  129. data/lib/active_record/core.rb +252 -230
  130. data/lib/active_record/counter_cache.rb +70 -49
  131. data/lib/active_record/database_configurations/database_config.rb +37 -0
  132. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  133. data/lib/active_record/database_configurations/url_config.rb +78 -0
  134. data/lib/active_record/database_configurations.rb +233 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +87 -106
  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 +22 -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 +152 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  147. data/lib/active_record/fixtures.rb +227 -501
  148. data/lib/active_record/gem_version.rb +6 -4
  149. data/lib/active_record/inheritance.rb +158 -115
  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 +86 -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/resolver/session.rb +45 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  160. data/lib/active_record/middleware/database_selector.rb +74 -0
  161. data/lib/active_record/migration/command_recorder.rb +166 -91
  162. data/lib/active_record/migration/compatibility.rb +244 -0
  163. data/lib/active_record/migration/join_table.rb +8 -7
  164. data/lib/active_record/migration.rb +623 -305
  165. data/lib/active_record/model_schema.rb +313 -112
  166. data/lib/active_record/nested_attributes.rb +263 -223
  167. data/lib/active_record/no_touching.rb +15 -2
  168. data/lib/active_record/null_relation.rb +24 -38
  169. data/lib/active_record/persistence.rb +557 -126
  170. data/lib/active_record/query_cache.rb +19 -23
  171. data/lib/active_record/querying.rb +44 -30
  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 +331 -185
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +430 -281
  179. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  180. data/lib/active_record/relation/batches.rb +206 -55
  181. data/lib/active_record/relation/calculations.rb +268 -254
  182. data/lib/active_record/relation/delegation.rb +75 -84
  183. data/lib/active_record/relation/finder_methods.rb +285 -241
  184. data/lib/active_record/relation/from_clause.rb +30 -0
  185. data/lib/active_record/relation/merger.rb +78 -88
  186. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
  187. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  188. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  189. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  190. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  191. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  192. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  193. data/lib/active_record/relation/predicate_builder.rb +110 -119
  194. data/lib/active_record/relation/query_attribute.rb +50 -0
  195. data/lib/active_record/relation/query_methods.rb +603 -397
  196. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  197. data/lib/active_record/relation/spawn_methods.rb +11 -14
  198. data/lib/active_record/relation/where_clause.rb +189 -0
  199. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  200. data/lib/active_record/relation.rb +530 -341
  201. data/lib/active_record/result.rb +79 -43
  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/default.rb +98 -83
  208. data/lib/active_record/scoping/named.rb +86 -33
  209. data/lib/active_record/scoping.rb +45 -27
  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 +90 -0
  216. data/lib/active_record/tasks/database_tasks.rb +307 -100
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +55 -100
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +80 -41
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +37 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +225 -0
  222. data/lib/active_record/timestamp.rb +86 -41
  223. data/lib/active_record/touch_later.rb +65 -0
  224. data/lib/active_record/transactions.rb +223 -157
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  227. data/lib/active_record/type/date.rb +4 -45
  228. data/lib/active_record/type/date_time.rb +4 -49
  229. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  230. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  231. data/lib/active_record/type/internal/timezone.rb +17 -0
  232. data/lib/active_record/type/json.rb +30 -0
  233. data/lib/active_record/type/serialized.rb +23 -15
  234. data/lib/active_record/type/text.rb +2 -2
  235. data/lib/active_record/type/time.rb +11 -16
  236. data/lib/active_record/type/type_map.rb +16 -19
  237. data/lib/active_record/type/unsigned_integer.rb +9 -8
  238. data/lib/active_record/type.rb +77 -23
  239. data/lib/active_record/type_caster/connection.rb +34 -0
  240. data/lib/active_record/type_caster/map.rb +20 -0
  241. data/lib/active_record/type_caster.rb +9 -0
  242. data/lib/active_record/validations/absence.rb +25 -0
  243. data/lib/active_record/validations/associated.rb +12 -4
  244. data/lib/active_record/validations/length.rb +26 -0
  245. data/lib/active_record/validations/presence.rb +14 -13
  246. data/lib/active_record/validations/uniqueness.rb +42 -55
  247. data/lib/active_record/validations.rb +38 -35
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/active_record.rb +42 -22
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes/attribute.rb +37 -0
  252. data/lib/arel/attributes.rb +22 -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/and.rb +32 -0
  266. data/lib/arel/nodes/ascending.rb +23 -0
  267. data/lib/arel/nodes/binary.rb +52 -0
  268. data/lib/arel/nodes/bind_param.rb +36 -0
  269. data/lib/arel/nodes/case.rb +55 -0
  270. data/lib/arel/nodes/casted.rb +50 -0
  271. data/lib/arel/nodes/comment.rb +29 -0
  272. data/lib/arel/nodes/count.rb +12 -0
  273. data/lib/arel/nodes/delete_statement.rb +45 -0
  274. data/lib/arel/nodes/descending.rb +23 -0
  275. data/lib/arel/nodes/equality.rb +18 -0
  276. data/lib/arel/nodes/extract.rb +24 -0
  277. data/lib/arel/nodes/false.rb +16 -0
  278. data/lib/arel/nodes/full_outer_join.rb +8 -0
  279. data/lib/arel/nodes/function.rb +44 -0
  280. data/lib/arel/nodes/grouping.rb +8 -0
  281. data/lib/arel/nodes/in.rb +8 -0
  282. data/lib/arel/nodes/infix_operation.rb +80 -0
  283. data/lib/arel/nodes/inner_join.rb +8 -0
  284. data/lib/arel/nodes/insert_statement.rb +37 -0
  285. data/lib/arel/nodes/join_source.rb +20 -0
  286. data/lib/arel/nodes/matches.rb +18 -0
  287. data/lib/arel/nodes/named_function.rb +23 -0
  288. data/lib/arel/nodes/node.rb +50 -0
  289. data/lib/arel/nodes/node_expression.rb +13 -0
  290. data/lib/arel/nodes/outer_join.rb +8 -0
  291. data/lib/arel/nodes/over.rb +15 -0
  292. data/lib/arel/nodes/regexp.rb +16 -0
  293. data/lib/arel/nodes/right_outer_join.rb +8 -0
  294. data/lib/arel/nodes/select_core.rb +67 -0
  295. data/lib/arel/nodes/select_statement.rb +41 -0
  296. data/lib/arel/nodes/sql_literal.rb +16 -0
  297. data/lib/arel/nodes/string_join.rb +11 -0
  298. data/lib/arel/nodes/table_alias.rb +27 -0
  299. data/lib/arel/nodes/terminal.rb +16 -0
  300. data/lib/arel/nodes/true.rb +16 -0
  301. data/lib/arel/nodes/unary.rb +45 -0
  302. data/lib/arel/nodes/unary_operation.rb +20 -0
  303. data/lib/arel/nodes/unqualified_column.rb +22 -0
  304. data/lib/arel/nodes/update_statement.rb +41 -0
  305. data/lib/arel/nodes/values_list.rb +9 -0
  306. data/lib/arel/nodes/window.rb +126 -0
  307. data/lib/arel/nodes/with.rb +11 -0
  308. data/lib/arel/nodes.rb +68 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +256 -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/depth_first.rb +203 -0
  316. data/lib/arel/visitors/dot.rb +296 -0
  317. data/lib/arel/visitors/ibm_db.rb +34 -0
  318. data/lib/arel/visitors/informix.rb +62 -0
  319. data/lib/arel/visitors/mssql.rb +156 -0
  320. data/lib/arel/visitors/mysql.rb +83 -0
  321. data/lib/arel/visitors/oracle.rb +158 -0
  322. data/lib/arel/visitors/oracle12.rb +65 -0
  323. data/lib/arel/visitors/postgresql.rb +109 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +888 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/visitors/where_sql.rb +22 -0
  328. data/lib/arel/visitors.rb +20 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/arel.rb +62 -0
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -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/migration_generator.rb +42 -37
  334. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  335. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -2
  336. data/lib/rails/generators/active_record/migration.rb +30 -1
  337. data/lib/rails/generators/active_record/model/model_generator.rb +18 -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. data/lib/rails/generators/active_record.rb +7 -5
  341. metadata +168 -59
  342. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  343. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  344. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  345. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  346. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  347. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  348. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  349. data/lib/active_record/attribute.rb +0 -163
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/attribute_set.rb +0 -81
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -31
  363. data/lib/active_record/type/decimal.rb +0 -64
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -59
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -40
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -110
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -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,66 @@ 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
+ if type
187
+ klass_scope.where!(type => foreign_klass.polymorphic_name)
188
+ end
189
+
190
+ scope_chain_items.inject(klass_scope, &:merge!)
191
+
192
+ key = join_keys.key
193
+ foreign_key = join_keys.foreign_key
194
+
195
+ klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
196
+
197
+ if klass.finder_needs_type_condition?
198
+ klass_scope.where!(klass.send(:type_condition, table))
199
+ end
200
+
201
+ klass_scope
202
+ end
203
+
204
+ def join_scopes(table, predicate_builder) # :nodoc:
205
+ if scope
206
+ [scope_for(build_scope(table, predicate_builder))]
207
+ else
208
+ []
209
+ end
210
+ end
211
+
212
+ def klass_join_scope(table, predicate_builder) # :nodoc:
213
+ relation = build_scope(table, predicate_builder)
214
+ klass.scope_for_association(relation)
164
215
  end
165
216
 
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
217
+ def constraints
218
+ chain.flat_map(&:scopes)
219
+ end
171
220
 
172
- macro
221
+ def counter_cache_column
222
+ if belongs_to?
223
+ if options[:counter_cache] == true
224
+ "#{active_record.name.demodulize.underscore.pluralize}_count"
225
+ elsif options[:counter_cache]
226
+ options[:counter_cache].to_s
227
+ end
228
+ else
229
+ options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
230
+ end
173
231
  end
174
232
 
175
233
  def inverse_of
@@ -185,17 +243,88 @@ module ActiveRecord
185
243
  end
186
244
  end
187
245
  end
246
+
247
+ # This shit is nasty. We need to avoid the following situation:
248
+ #
249
+ # * An associated record is deleted via record.destroy
250
+ # * Hence the callbacks run, and they find a belongs_to on the record with a
251
+ # :counter_cache options which points back at our owner. So they update the
252
+ # counter cache.
253
+ # * In which case, we must make sure to *not* update the counter cache, or else
254
+ # it will be decremented twice.
255
+ #
256
+ # Hence this method.
257
+ def inverse_which_updates_counter_cache
258
+ return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
259
+ @inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
260
+ inverse.counter_cache_column == counter_cache_column
261
+ end
262
+ end
263
+ alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
264
+
265
+ def inverse_updates_counter_in_memory?
266
+ inverse_of && inverse_which_updates_counter_cache == inverse_of
267
+ end
268
+
269
+ # Returns whether a counter cache should be used for this association.
270
+ #
271
+ # The counter_cache option must be given on either the owner or inverse
272
+ # association, and the column must be present on the owner.
273
+ def has_cached_counter?
274
+ options[:counter_cache] ||
275
+ inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
276
+ !!active_record.columns_hash[counter_cache_column]
277
+ end
278
+
279
+ def counter_must_be_updated_by_has_many?
280
+ !inverse_updates_counter_in_memory? && has_cached_counter?
281
+ end
282
+
283
+ def alias_candidate(name)
284
+ "#{plural_name}_#{name}"
285
+ end
286
+
287
+ def chain
288
+ collect_join_chain
289
+ end
290
+
291
+ def get_join_keys(association_klass)
292
+ JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
293
+ end
294
+
295
+ def build_scope(table, predicate_builder = predicate_builder(table))
296
+ Relation.create(
297
+ klass,
298
+ table: table,
299
+ predicate_builder: predicate_builder
300
+ )
301
+ end
302
+
303
+ def join_primary_key(*)
304
+ foreign_key
305
+ end
306
+
307
+ def join_foreign_key
308
+ active_record_primary_key
309
+ end
310
+
311
+ protected
312
+ def actual_source_reflection # FIXME: this is a horrible name
313
+ self
314
+ end
315
+
316
+ private
317
+ def predicate_builder(table)
318
+ PredicateBuilder.new(TableMetadata.new(klass, table))
319
+ end
320
+
321
+ def primary_key(klass)
322
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
323
+ end
188
324
  end
325
+
189
326
  # Base class for AggregateReflection and AssociationReflection. Objects of
190
327
  # 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
328
  class MacroReflection < AbstractReflection
200
329
  # Returns the name of the macro.
201
330
  #
@@ -226,9 +355,8 @@ module ActiveRecord
226
355
  end
227
356
 
228
357
  def autosave=(autosave)
229
- @automatic_inverse_of = false
230
358
  @options[:autosave] = autosave
231
- _, parent_reflection = self.parent_reflection
359
+ parent_reflection = self.parent_reflection
232
360
  if parent_reflection
233
361
  parent_reflection.autosave = autosave
234
362
  end
@@ -238,6 +366,17 @@ module ActiveRecord
238
366
  #
239
367
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
240
368
  # <tt>has_many :clients</tt> returns the Client class
369
+ #
370
+ # class Company < ActiveRecord::Base
371
+ # has_many :clients
372
+ # end
373
+ #
374
+ # Company.reflect_on_association(:clients).klass
375
+ # # => Client
376
+ #
377
+ # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
378
+ # a new association object. Use +build_association+ or +create_association+
379
+ # instead. This allows plugins to hook into association object creation.
241
380
  def klass
242
381
  @klass ||= compute_class(class_name)
243
382
  end
@@ -256,14 +395,17 @@ module ActiveRecord
256
395
  active_record == other_aggregation.active_record
257
396
  end
258
397
 
398
+ def scope_for(relation, owner = nil)
399
+ relation.instance_exec(owner, &scope) || relation
400
+ end
401
+
259
402
  private
260
403
  def derive_class_name
261
404
  name.to_s.camelize
262
405
  end
263
406
  end
264
407
 
265
-
266
- # Holds all the meta-data about an aggregation as it was specified in the
408
+ # Holds all the metadata about an aggregation as it was specified in the
267
409
  # Active Record class.
268
410
  class AggregateReflection < MacroReflection #:nodoc:
269
411
  def mapping
@@ -272,50 +414,37 @@ module ActiveRecord
272
414
  end
273
415
  end
274
416
 
275
- # Holds all the meta-data about an association as it was specified in the
417
+ # Holds all the metadata about an association as it was specified in the
276
418
  # Active Record class.
277
419
  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
420
  def compute_class(name)
421
+ if polymorphic?
422
+ raise ArgumentError, "Polymorphic associations do not support computing the class."
423
+ end
295
424
  active_record.send(:compute_type, name)
296
425
  end
297
426
 
298
427
  attr_reader :type, :foreign_type
299
- attr_accessor :parent_reflection # [:name, Reflection]
428
+ attr_accessor :parent_reflection # Reflection
300
429
 
301
430
  def initialize(name, scope, options, active_record)
302
431
  super
303
- @automatic_inverse_of = nil
304
432
  @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
305
- @foreign_type = options[:foreign_type] || "#{name}_type"
433
+ @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
306
434
  @constructable = calculate_constructable(macro, options)
307
- @association_scope_cache = {}
308
- @scope_lock = Mutex.new
435
+ @association_scope_cache = Concurrent::Map.new
436
+
437
+ if options[:class_name] && options[:class_name].class == Class
438
+ raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
439
+ end
309
440
  end
310
441
 
311
- def association_scope_cache(conn, owner)
442
+ def association_scope_cache(conn, owner, &block)
312
443
  key = conn.prepared_statements
313
444
  if polymorphic?
314
445
  key = [key, owner._read_attribute(@foreign_type)]
315
446
  end
316
- @association_scope_cache[key] ||= @scope_lock.synchronize {
317
- @association_scope_cache[key] ||= yield
318
- }
447
+ @association_scope_cache.compute_if_absent(key) { StatementCache.create(conn, &block) }
319
448
  end
320
449
 
321
450
  def constructable? # :nodoc:
@@ -343,14 +472,6 @@ module ActiveRecord
343
472
  @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
344
473
  end
345
474
 
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
475
  def check_validity!
355
476
  check_validity_of_inverse!
356
477
  end
@@ -358,21 +479,18 @@ module ActiveRecord
358
479
  def check_preloadable!
359
480
  return unless scope
360
481
 
361
- if scope.arity > 0
362
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
482
+ unless scope.arity == 0
483
+ raise ArgumentError, <<-MSG.squish
363
484
  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.
485
+ block takes an argument). Preloading instance dependent scopes is
486
+ not supported.
369
487
  MSG
370
488
  end
371
489
  end
372
490
  alias :check_eager_loadable! :check_preloadable!
373
491
 
374
492
  def join_id_for(owner) # :nodoc:
375
- owner[active_record_primary_key]
493
+ owner[join_foreign_key]
376
494
  end
377
495
 
378
496
  def through_reflection
@@ -385,18 +503,22 @@ module ActiveRecord
385
503
 
386
504
  # A chain of reflections from this one back to the owner. For more see the explanation in
387
505
  # ThroughReflection.
388
- def chain
506
+ def collect_join_chain
389
507
  [self]
390
508
  end
391
509
 
510
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
511
+ # SQL queries on associations.
512
+ def clear_association_scope_cache # :nodoc:
513
+ @association_scope_cache.clear
514
+ end
515
+
392
516
  def nested?
393
517
  false
394
518
  end
395
519
 
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]] : [[]]
520
+ def has_scope?
521
+ scope
400
522
  end
401
523
 
402
524
  def has_inverse?
@@ -444,69 +566,48 @@ module ActiveRecord
444
566
  # Returns +true+ if +self+ is a +has_one+ reflection.
445
567
  def has_one?; false; end
446
568
 
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
569
+ def association_class; raise NotImplementedError; end
469
570
 
470
571
  def polymorphic?
471
572
  options[:polymorphic]
472
573
  end
473
574
 
474
575
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
475
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
576
+ INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
476
577
 
477
- protected
578
+ def add_as_source(seed)
579
+ seed
580
+ end
478
581
 
479
- def actual_source_reflection # FIXME: this is a horrible name
480
- self
481
- end
582
+ def add_as_polymorphic_through(reflection, seed)
583
+ seed + [PolymorphicReflection.new(self, reflection)]
584
+ end
482
585
 
483
- private
586
+ def add_as_through(seed)
587
+ seed + [self]
588
+ end
589
+
590
+ def extensions
591
+ Array(options[:extend])
592
+ end
484
593
 
594
+ private
485
595
  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
596
+ true
494
597
  end
495
598
 
496
599
  # Attempts to find the inverse association name automatically.
497
600
  # If it cannot find a suitable inverse association name, it returns
498
- # nil.
601
+ # +nil+.
499
602
  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
603
+ unless defined?(@inverse_name)
604
+ @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
506
605
  end
606
+
607
+ @inverse_name
507
608
  end
508
609
 
509
- # returns either nil or the inverse association name that it finds.
610
+ # returns either +nil+ or the inverse association name that it finds.
510
611
  def automatic_inverse_of
511
612
  if can_find_inverse_of_automatically?(self)
512
613
  inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
@@ -520,23 +621,18 @@ module ActiveRecord
520
621
  end
521
622
 
522
623
  if valid_inverse_reflection?(reflection)
523
- return inverse_name
624
+ inverse_name
524
625
  end
525
626
  end
526
-
527
- false
528
627
  end
529
628
 
530
629
  # Checks if the inverse reflection that is returned from the
531
630
  # +automatic_inverse_of+ method is a valid reflection. We must
532
631
  # make sure that the reflection's active_record name matches up
533
632
  # 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
633
  def valid_inverse_reflection?(reflection)
538
634
  reflection &&
539
- klass.name == reflection.active_record.name &&
635
+ klass <= reflection.active_record &&
540
636
  can_find_inverse_of_automatically?(reflection)
541
637
  end
542
638
 
@@ -544,9 +640,8 @@ module ActiveRecord
544
640
  # us from being able to guess the inverse automatically. First, the
545
641
  # <tt>inverse_of</tt> option cannot be set to false. Second, we must
546
642
  # 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.
643
+ # Third, we must not have options such as <tt>:foreign_key</tt>
644
+ # which prevent us from correctly guessing the inverse association.
550
645
  #
551
646
  # Anything with a scope can additionally ruin our attempt at finding an
552
647
  # inverse, so we exclude reflections with scopes.
@@ -576,56 +671,77 @@ module ActiveRecord
576
671
  def derive_join_table
577
672
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
578
673
  end
579
-
580
- def primary_key(klass)
581
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
582
- end
583
674
  end
584
675
 
585
676
  class HasManyReflection < AssociationReflection # :nodoc:
586
- def initialize(name, scope, options, active_record)
587
- super(name, scope, options, active_record)
588
- end
589
-
590
677
  def macro; :has_many; end
591
678
 
592
679
  def collection?; true; end
593
- end
594
680
 
595
- class HasOneReflection < AssociationReflection # :nodoc:
596
- def initialize(name, scope, options, active_record)
597
- super(name, scope, options, active_record)
681
+ def association_class
682
+ if options[:through]
683
+ Associations::HasManyThroughAssociation
684
+ else
685
+ Associations::HasManyAssociation
686
+ end
598
687
  end
599
688
 
689
+ def association_primary_key(klass = nil)
690
+ primary_key(klass || self.klass)
691
+ end
692
+ end
693
+
694
+ class HasOneReflection < AssociationReflection # :nodoc:
600
695
  def macro; :has_one; end
601
696
 
602
697
  def has_one?; true; end
603
- end
604
698
 
605
- class BelongsToReflection < AssociationReflection # :nodoc:
606
- def initialize(name, scope, options, active_record)
607
- super(name, scope, options, active_record)
699
+ def association_class
700
+ if options[:through]
701
+ Associations::HasOneThroughAssociation
702
+ else
703
+ Associations::HasOneAssociation
704
+ end
608
705
  end
609
706
 
707
+ private
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
617
724
  end
618
725
 
619
- def join_id_for(owner) # :nodoc:
620
- owner[foreign_key]
726
+ def join_primary_key(klass = nil)
727
+ polymorphic? ? association_primary_key(klass) : association_primary_key
621
728
  end
622
- end
623
729
 
624
- class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
625
- def initialize(name, scope, options, active_record)
626
- super
730
+ def join_foreign_key
731
+ foreign_key
627
732
  end
628
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:
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
963
+
964
+ def add_as_through(seed)
965
+ collect_join_reflections(seed + [self])
966
+ end
869
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