activerecord 4.2.0 → 6.0.5.1

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

Potentially problematic release.


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

Files changed (373) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +852 -801
  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 +267 -249
  9. data/lib/active_record/association_relation.rb +26 -6
  10. data/lib/active_record/associations/alias_tracker.rb +29 -36
  11. data/lib/active_record/associations/association.rb +137 -55
  12. data/lib/active_record/associations/association_scope.rb +110 -132
  13. data/lib/active_record/associations/belongs_to_association.rb +67 -54
  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 -29
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +58 -70
  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 +150 -275
  23. data/lib/active_record/associations/collection_proxy.rb +253 -152
  24. data/lib/active_record/associations/foreign_association.rb +20 -0
  25. data/lib/active_record/associations/has_many_association.rb +35 -84
  26. data/lib/active_record/associations/has_many_through_association.rb +62 -80
  27. data/lib/active_record/associations/has_one_association.rb +62 -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 +43 -78
  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 +159 -162
  33. data/lib/active_record/associations/preloader/association.rb +102 -113
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  35. data/lib/active_record/associations/preloader.rb +96 -95
  36. data/lib/active_record/associations/singular_association.rb +18 -45
  37. data/lib/active_record/associations/through_association.rb +49 -24
  38. data/lib/active_record/associations.rb +1737 -1596
  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 +14 -5
  42. data/lib/active_record/attribute_methods/dirty.rb +174 -134
  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 +61 -37
  48. data/lib/active_record/attribute_methods/write.rb +33 -56
  49. data/lib/active_record/attribute_methods.rb +124 -143
  50. data/lib/active_record/attributes.rb +213 -74
  51. data/lib/active_record/autosave_association.rb +125 -54
  52. data/lib/active_record/base.rb +60 -49
  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 +36 -13
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +810 -291
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +253 -108
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -24
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +171 -53
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -47
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +383 -239
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +736 -235
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +190 -87
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -192
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +536 -600
  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 +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -196
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +71 -115
  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 -57
  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 +5 -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 +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  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 +70 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  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 +465 -291
  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 +565 -363
  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 -364
  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 +277 -233
  130. data/lib/active_record/counter_cache.rb +71 -50
  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 +172 -89
  138. data/lib/active_record/errors.rb +189 -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 +11 -6
  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 +225 -497
  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 +48 -0
  154. data/lib/active_record/locale/en.yml +3 -2
  155. data/lib/active_record/locking/optimistic.rb +99 -98
  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 +636 -290
  165. data/lib/active_record/model_schema.rb +344 -112
  166. data/lib/active_record/nested_attributes.rb +265 -215
  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 +559 -125
  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 +166 -47
  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 +341 -202
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +461 -302
  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 +270 -249
  182. data/lib/active_record/relation/delegation.rb +76 -84
  183. data/lib/active_record/relation/finder_methods.rb +287 -255
  184. data/lib/active_record/relation/from_clause.rb +30 -0
  185. data/lib/active_record/relation/merger.rb +86 -68
  186. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -25
  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 +112 -92
  194. data/lib/active_record/relation/query_attribute.rb +50 -0
  195. data/lib/active_record/relation/query_methods.rb +612 -392
  196. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  197. data/lib/active_record/relation/spawn_methods.rb +18 -17
  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 +533 -340
  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 -20
  207. data/lib/active_record/scoping/default.rb +98 -82
  208. data/lib/active_record/scoping/named.rb +91 -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 +309 -99
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +58 -89
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -31
  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 +243 -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 +222 -146
  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 -41
  228. data/lib/active_record/type/date_time.rb +4 -38
  229. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  230. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  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 +29 -15
  234. data/lib/active_record/type/text.rb +2 -2
  235. data/lib/active_record/type/time.rb +21 -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 +43 -46
  247. data/lib/active_record/validations.rb +38 -35
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/active_record.rb +44 -21
  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 -8
  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.rb +7 -5
  340. metadata +174 -63
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -149
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  351. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  352. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  353. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  354. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  355. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  356. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  359. data/lib/active_record/type/big_integer.rb +0 -13
  360. data/lib/active_record/type/binary.rb +0 -50
  361. data/lib/active_record/type/boolean.rb +0 -30
  362. data/lib/active_record/type/decimal.rb +0 -40
  363. data/lib/active_record/type/decorator.rb +0 -14
  364. data/lib/active_record/type/float.rb +0 -19
  365. data/lib/active_record/type/integer.rb +0 -55
  366. data/lib/active_record/type/mutable.rb +0 -16
  367. data/lib/active_record/type/numeric.rb +0 -36
  368. data/lib/active_record/type/string.rb +0 -36
  369. data/lib/active_record/type/time_value.rb +0 -38
  370. data/lib/active_record/type/value.rb +0 -101
  371. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  372. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  373. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,5 +1,6 @@
1
- require 'thread'
2
- require 'active_support/core_ext/string/filters'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/filters"
3
4
 
4
5
  module ActiveRecord
5
6
  # = Active Record Reflection
@@ -7,41 +8,46 @@ module ActiveRecord
7
8
  extend ActiveSupport::Concern
8
9
 
9
10
  included do
10
- class_attribute :_reflections
11
- class_attribute :aggregate_reflections
12
- self._reflections = {}
13
- self.aggregate_reflections = {}
11
+ class_attribute :_reflections, instance_writer: false, default: {}
12
+ class_attribute :aggregate_reflections, instance_writer: false, default: {}
14
13
  end
15
14
 
16
- def self.create(macro, name, scope, options, ar)
17
- klass = case macro
18
- when :composed_of
19
- AggregateReflection
20
- when :has_many
21
- HasManyReflection
22
- when :has_one
23
- HasOneReflection
24
- when :belongs_to
25
- BelongsToReflection
26
- else
27
- raise "Unsupported Macro: #{macro}"
28
- end
29
-
30
- reflection = klass.new(name, scope, options, ar)
31
- options[:through] ? ThroughReflection.new(reflection) : reflection
32
- end
15
+ class << self
16
+ def create(macro, name, scope, options, ar)
17
+ reflection = reflection_class_for(macro).new(name, scope, options, ar)
18
+ options[:through] ? ThroughReflection.new(reflection) : reflection
19
+ end
33
20
 
34
- def self.add_reflection(ar, name, reflection)
35
- ar._reflections = ar._reflections.merge(name.to_s => reflection)
36
- end
21
+ def add_reflection(ar, name, reflection)
22
+ ar.clear_reflections_cache
23
+ name = -name.to_s
24
+ ar._reflections = ar._reflections.except(name).merge!(name => reflection)
25
+ end
37
26
 
38
- def self.add_aggregate_reflection(ar, name, reflection)
39
- ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
27
+ def add_aggregate_reflection(ar, name, reflection)
28
+ ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
29
+ end
30
+
31
+ private
32
+ def reflection_class_for(macro)
33
+ case macro
34
+ when :composed_of
35
+ AggregateReflection
36
+ when :has_many
37
+ HasManyReflection
38
+ when :has_one
39
+ HasOneReflection
40
+ when :belongs_to
41
+ BelongsToReflection
42
+ else
43
+ raise "Unsupported Macro: #{macro}"
44
+ end
45
+ end
40
46
  end
41
47
 
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
48
+ # \Reflection enables the ability to examine the associations and aggregations of
49
+ # Active Record classes and objects. This information, for example,
50
+ # can be used in a form builder that takes an Active Record object
45
51
  # and creates input fields for all of the attributes depending on their type
46
52
  # and displays the associations to other objects.
47
53
  #
@@ -61,22 +67,27 @@ module ActiveRecord
61
67
  aggregate_reflections[aggregation.to_s]
62
68
  end
63
69
 
64
- # Returns a Hash of name of the reflection as the key and a AssociationReflection as the value.
70
+ # Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
65
71
  #
66
72
  # Account.reflections # => {"balance" => AggregateReflection}
67
73
  #
68
- # @api public
69
74
  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
75
+ @__reflections ||= begin
76
+ ref = {}
77
+
78
+ _reflections.each do |name, reflection|
79
+ parent_reflection = reflection.parent_reflection
80
+
81
+ if parent_reflection
82
+ parent_name = parent_reflection.name
83
+ ref[parent_name.to_s] = parent_reflection
84
+ else
85
+ ref[name] = reflection
86
+ end
77
87
  end
88
+
89
+ ref
78
90
  end
79
- ref
80
91
  end
81
92
 
82
93
  # Returns an array of AssociationReflection objects for all the
@@ -89,10 +100,10 @@ module ActiveRecord
89
100
  # Account.reflect_on_all_associations # returns an array of all associations
90
101
  # Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
91
102
  #
92
- # @api public
93
103
  def reflect_on_all_associations(macro = nil)
94
104
  association_reflections = reflections.values
95
- macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
105
+ association_reflections.select! { |reflection| reflection.macro == macro } if macro
106
+ association_reflections
96
107
  end
97
108
 
98
109
  # Returns the AssociationReflection object for the +association+ (use the symbol).
@@ -100,27 +111,42 @@ module ActiveRecord
100
111
  # Account.reflect_on_association(:owner) # returns the owner AssociationReflection
101
112
  # Invoice.reflect_on_association(:line_items).macro # returns :has_many
102
113
  #
103
- # @api public
104
114
  def reflect_on_association(association)
105
115
  reflections[association.to_s]
106
116
  end
107
117
 
108
- # @api private
109
118
  def _reflect_on_association(association) #:nodoc:
110
119
  _reflections[association.to_s]
111
120
  end
112
121
 
113
122
  # Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
114
- #
115
- # @api public
116
123
  def reflect_on_all_autosave_associations
117
124
  reflections.values.select { |reflection| reflection.options[:autosave] }
118
125
  end
126
+
127
+ def clear_reflections_cache # :nodoc:
128
+ @__reflections = nil
129
+ end
119
130
  end
120
131
 
121
- # Holds all the methods that are shared between MacroReflection, AssociationReflection
122
- # and ThroughReflection
132
+ # Holds all the methods that are shared between MacroReflection and ThroughReflection.
133
+ #
134
+ # AbstractReflection
135
+ # MacroReflection
136
+ # AggregateReflection
137
+ # AssociationReflection
138
+ # HasManyReflection
139
+ # HasOneReflection
140
+ # BelongsToReflection
141
+ # HasAndBelongsToManyReflection
142
+ # ThroughReflection
143
+ # PolymorphicReflection
144
+ # RuntimeReflection
123
145
  class AbstractReflection # :nodoc:
146
+ def through_reflection?
147
+ false
148
+ end
149
+
124
150
  def table_name
125
151
  klass.table_name
126
152
  end
@@ -131,14 +157,6 @@ module ActiveRecord
131
157
  klass.new(attributes, &block)
132
158
  end
133
159
 
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
160
  # Returns the class name for the macro.
143
161
  #
144
162
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
@@ -149,29 +167,163 @@ module ActiveRecord
149
167
 
150
168
  JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
151
169
 
152
- def join_keys(assoc_klass)
153
- JoinKeys.new(foreign_key, active_record_primary_key)
170
+ def join_keys
171
+ @join_keys ||= get_join_keys(klass)
172
+ end
173
+
174
+ # Returns a list of scopes that should be applied for this Reflection
175
+ # object when querying the database.
176
+ def scopes
177
+ scope ? [scope] : []
178
+ end
179
+
180
+ def join_scope(table, foreign_table, foreign_klass)
181
+ predicate_builder = predicate_builder(table)
182
+ scope_chain_items = join_scopes(table, predicate_builder)
183
+ klass_scope = klass_join_scope(table, predicate_builder)
184
+
185
+ if type
186
+ klass_scope.where!(type => foreign_klass.polymorphic_name)
187
+ end
188
+
189
+ scope_chain_items.inject(klass_scope, &:merge!)
190
+
191
+ key = join_keys.key
192
+ foreign_key = join_keys.foreign_key
193
+
194
+ klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
195
+
196
+ if klass.finder_needs_type_condition?
197
+ klass_scope.where!(klass.send(:type_condition, table))
198
+ end
199
+
200
+ klass_scope
201
+ end
202
+
203
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
204
+ if scope
205
+ [scope_for(build_scope(table, predicate_builder, klass))]
206
+ else
207
+ []
208
+ end
209
+ end
210
+
211
+ def klass_join_scope(table, predicate_builder) # :nodoc:
212
+ relation = build_scope(table, predicate_builder)
213
+ klass.scope_for_association(relation)
214
+ end
215
+
216
+ def constraints
217
+ chain.flat_map(&:scopes)
218
+ end
219
+
220
+ def counter_cache_column
221
+ if belongs_to?
222
+ if options[:counter_cache] == true
223
+ "#{active_record.name.demodulize.underscore.pluralize}_count"
224
+ elsif options[:counter_cache]
225
+ options[:counter_cache].to_s
226
+ end
227
+ else
228
+ options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
229
+ end
154
230
  end
155
231
 
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
232
+ def inverse_of
233
+ return unless inverse_name
234
+
235
+ @inverse_of ||= klass._reflect_on_association inverse_name
236
+ end
237
+
238
+ def check_validity_of_inverse!
239
+ unless polymorphic?
240
+ if has_inverse? && inverse_of.nil?
241
+ raise InverseOfAssociationNotFoundError.new(self)
242
+ end
243
+ end
244
+ end
245
+
246
+ # This shit is nasty. We need to avoid the following situation:
247
+ #
248
+ # * An associated record is deleted via record.destroy
249
+ # * Hence the callbacks run, and they find a belongs_to on the record with a
250
+ # :counter_cache options which points back at our owner. So they update the
251
+ # counter cache.
252
+ # * In which case, we must make sure to *not* update the counter cache, or else
253
+ # it will be decremented twice.
254
+ #
255
+ # Hence this method.
256
+ def inverse_which_updates_counter_cache
257
+ return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
258
+ @inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
259
+ inverse.counter_cache_column == counter_cache_column
260
+ end
261
+ end
262
+ alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
161
263
 
162
- macro
264
+ def inverse_updates_counter_in_memory?
265
+ inverse_of && inverse_which_updates_counter_cache == inverse_of
163
266
  end
267
+
268
+ # Returns whether a counter cache should be used for this association.
269
+ #
270
+ # The counter_cache option must be given on either the owner or inverse
271
+ # association, and the column must be present on the owner.
272
+ def has_cached_counter?
273
+ options[:counter_cache] ||
274
+ inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
275
+ !!active_record.columns_hash[counter_cache_column]
276
+ end
277
+
278
+ def counter_must_be_updated_by_has_many?
279
+ !inverse_updates_counter_in_memory? && has_cached_counter?
280
+ end
281
+
282
+ def alias_candidate(name)
283
+ "#{plural_name}_#{name}"
284
+ end
285
+
286
+ def chain
287
+ collect_join_chain
288
+ end
289
+
290
+ def get_join_keys(association_klass)
291
+ JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
292
+ end
293
+
294
+ def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
295
+ Relation.create(
296
+ klass,
297
+ table: table,
298
+ predicate_builder: predicate_builder
299
+ )
300
+ end
301
+
302
+ def join_primary_key(*)
303
+ foreign_key
304
+ end
305
+
306
+ def join_foreign_key
307
+ active_record_primary_key
308
+ end
309
+
310
+ protected
311
+ def actual_source_reflection # FIXME: this is a horrible name
312
+ self
313
+ end
314
+
315
+ private
316
+ def predicate_builder(table)
317
+ PredicateBuilder.new(TableMetadata.new(klass, table))
318
+ end
319
+
320
+ def primary_key(klass)
321
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
322
+ end
164
323
  end
324
+
165
325
  # Base class for AggregateReflection and AssociationReflection. Objects of
166
326
  # 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
327
  class MacroReflection < AbstractReflection
176
328
  # Returns the name of the macro.
177
329
  #
@@ -196,15 +348,14 @@ module ActiveRecord
196
348
  @scope = scope
197
349
  @options = options
198
350
  @active_record = active_record
199
- @klass = options[:class]
351
+ @klass = options[:anonymous_class]
200
352
  @plural_name = active_record.pluralize_table_names ?
201
353
  name.to_s.pluralize : name.to_s
202
354
  end
203
355
 
204
356
  def autosave=(autosave)
205
- @automatic_inverse_of = false
206
357
  @options[:autosave] = autosave
207
- _, parent_reflection = self.parent_reflection
358
+ parent_reflection = self.parent_reflection
208
359
  if parent_reflection
209
360
  parent_reflection.autosave = autosave
210
361
  end
@@ -214,6 +365,17 @@ module ActiveRecord
214
365
  #
215
366
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
216
367
  # <tt>has_many :clients</tt> returns the Client class
368
+ #
369
+ # class Company < ActiveRecord::Base
370
+ # has_many :clients
371
+ # end
372
+ #
373
+ # Company.reflect_on_association(:clients).klass
374
+ # # => Client
375
+ #
376
+ # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
377
+ # a new association object. Use +build_association+ or +create_association+
378
+ # instead. This allows plugins to hook into association object creation.
217
379
  def klass
218
380
  @klass ||= compute_class(class_name)
219
381
  end
@@ -232,14 +394,17 @@ module ActiveRecord
232
394
  active_record == other_aggregation.active_record
233
395
  end
234
396
 
397
+ def scope_for(relation, owner = nil)
398
+ relation.instance_exec(owner, &scope) || relation
399
+ end
400
+
235
401
  private
236
402
  def derive_class_name
237
403
  name.to_s.camelize
238
404
  end
239
405
  end
240
406
 
241
-
242
- # Holds all the meta-data about an aggregation as it was specified in the
407
+ # Holds all the metadata about an aggregation as it was specified in the
243
408
  # Active Record class.
244
409
  class AggregateReflection < MacroReflection #:nodoc:
245
410
  def mapping
@@ -248,50 +413,36 @@ module ActiveRecord
248
413
  end
249
414
  end
250
415
 
251
- # Holds all the meta-data about an association as it was specified in the
416
+ # Holds all the metadata about an association as it was specified in the
252
417
  # Active Record class.
253
418
  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
419
  def compute_class(name)
420
+ if polymorphic?
421
+ raise ArgumentError, "Polymorphic associations do not support computing the class."
422
+ end
271
423
  active_record.send(:compute_type, name)
272
424
  end
273
425
 
274
426
  attr_reader :type, :foreign_type
275
- attr_accessor :parent_reflection # [:name, Reflection]
427
+ attr_accessor :parent_reflection # Reflection
276
428
 
277
429
  def initialize(name, scope, options, active_record)
278
430
  super
279
- @automatic_inverse_of = nil
280
431
  @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
281
- @foreign_type = options[:foreign_type] || "#{name}_type"
432
+ @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
282
433
  @constructable = calculate_constructable(macro, options)
283
- @association_scope_cache = {}
284
- @scope_lock = Mutex.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)
288
- key = conn.prepared_statements
440
+ def association_scope_cache(klass, owner, &block)
441
+ key = self
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
+ klass.cached_find_by_statement(key, &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
+ klass.initialize_find_by_cache
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,51 @@ 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
472
583
 
473
- private
584
+ def add_as_through(seed)
585
+ seed + [self]
586
+ end
474
587
 
588
+ def extensions
589
+ Array(options[:extend])
590
+ end
591
+
592
+ private
475
593
  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
594
+ true
484
595
  end
485
596
 
486
597
  # Attempts to find the inverse association name automatically.
487
598
  # If it cannot find a suitable inverse association name, it returns
488
- # nil.
599
+ # +nil+.
489
600
  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
601
+ unless defined?(@inverse_name)
602
+ @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
496
603
  end
604
+
605
+ @inverse_name
497
606
  end
498
607
 
499
- # returns either nil or the inverse association name that it finds.
608
+ # returns either +nil+ or the inverse association name that it finds.
500
609
  def automatic_inverse_of
501
610
  if can_find_inverse_of_automatically?(self)
502
- inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name).to_sym
611
+ inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
503
612
 
504
613
  begin
505
614
  reflection = klass._reflect_on_association(inverse_name)
@@ -510,23 +619,18 @@ module ActiveRecord
510
619
  end
511
620
 
512
621
  if valid_inverse_reflection?(reflection)
513
- return inverse_name
622
+ inverse_name
514
623
  end
515
624
  end
516
-
517
- false
518
625
  end
519
626
 
520
627
  # Checks if the inverse reflection that is returned from the
521
628
  # +automatic_inverse_of+ method is a valid reflection. We must
522
629
  # make sure that the reflection's active_record name matches up
523
630
  # 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
631
  def valid_inverse_reflection?(reflection)
528
632
  reflection &&
529
- klass.name == reflection.active_record.name &&
633
+ klass <= reflection.active_record &&
530
634
  can_find_inverse_of_automatically?(reflection)
531
635
  end
532
636
 
@@ -534,9 +638,8 @@ module ActiveRecord
534
638
  # us from being able to guess the inverse automatically. First, the
535
639
  # <tt>inverse_of</tt> option cannot be set to false. Second, we must
536
640
  # 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.
641
+ # Third, we must not have options such as <tt>:foreign_key</tt>
642
+ # which prevent us from correctly guessing the inverse association.
540
643
  #
541
644
  # Anything with a scope can additionally ruin our attempt at finding an
542
645
  # inverse, so we exclude reflections with scopes.
@@ -566,56 +669,77 @@ module ActiveRecord
566
669
  def derive_join_table
567
670
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
568
671
  end
569
-
570
- def primary_key(klass)
571
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
572
- end
573
672
  end
574
673
 
575
674
  class HasManyReflection < AssociationReflection # :nodoc:
576
- def initialize(name, scope, options, active_record)
577
- super(name, scope, options, active_record)
578
- end
579
-
580
675
  def macro; :has_many; end
581
676
 
582
677
  def collection?; true; end
583
- end
584
678
 
585
- class HasOneReflection < AssociationReflection # :nodoc:
586
- def initialize(name, scope, options, active_record)
587
- super(name, scope, options, active_record)
679
+ def association_class
680
+ if options[:through]
681
+ Associations::HasManyThroughAssociation
682
+ else
683
+ Associations::HasManyAssociation
684
+ end
588
685
  end
589
686
 
687
+ def association_primary_key(klass = nil)
688
+ primary_key(klass || self.klass)
689
+ end
690
+ end
691
+
692
+ class HasOneReflection < AssociationReflection # :nodoc:
590
693
  def macro; :has_one; end
591
694
 
592
695
  def has_one?; true; end
593
- end
594
696
 
595
- class BelongsToReflection < AssociationReflection # :nodoc:
596
- def initialize(name, scope, options, active_record)
597
- super(name, scope, options, active_record)
697
+ def association_class
698
+ if options[:through]
699
+ Associations::HasOneThroughAssociation
700
+ else
701
+ Associations::HasOneAssociation
702
+ end
598
703
  end
599
704
 
705
+ private
706
+ def calculate_constructable(macro, options)
707
+ !options[:through]
708
+ end
709
+ end
710
+
711
+ class BelongsToReflection < AssociationReflection # :nodoc:
600
712
  def macro; :belongs_to; end
601
713
 
602
714
  def belongs_to?; true; end
603
715
 
604
- def join_keys(assoc_klass)
605
- key = polymorphic? ? association_primary_key(assoc_klass) : association_primary_key
606
- JoinKeys.new(key, foreign_key)
716
+ def association_class
717
+ if polymorphic?
718
+ Associations::BelongsToPolymorphicAssociation
719
+ else
720
+ Associations::BelongsToAssociation
721
+ end
607
722
  end
608
723
 
609
- def join_id_for(owner) # :nodoc:
610
- owner[foreign_key]
724
+ def join_primary_key(klass = nil)
725
+ polymorphic? ? association_primary_key(klass) : association_primary_key
611
726
  end
612
- end
613
727
 
614
- class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
615
- def initialize(name, scope, options, active_record)
616
- super
728
+ def join_foreign_key
729
+ foreign_key
617
730
  end
618
731
 
732
+ private
733
+ def can_find_inverse_of_automatically?(_)
734
+ !polymorphic? && super
735
+ end
736
+
737
+ def calculate_constructable(macro, options)
738
+ !polymorphic?
739
+ end
740
+ end
741
+
742
+ class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
619
743
  def macro; :has_and_belongs_to_many; end
620
744
 
621
745
  def collection?
@@ -623,19 +747,22 @@ module ActiveRecord
623
747
  end
624
748
  end
625
749
 
626
- # Holds all the meta-data about a :through association as it was specified
750
+ # Holds all the metadata about a :through association as it was specified
627
751
  # in the Active Record class.
628
752
  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
753
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
754
+ :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
632
755
 
633
756
  def initialize(delegate_reflection)
634
757
  @delegate_reflection = delegate_reflection
635
- @klass = delegate_reflection.options[:class]
758
+ @klass = delegate_reflection.options[:anonymous_class]
636
759
  @source_reflection_name = delegate_reflection.options[:source]
637
760
  end
638
761
 
762
+ def through_reflection?
763
+ true
764
+ end
765
+
639
766
  def klass
640
767
  @klass ||= delegate_reflection.compute_class(class_name)
641
768
  end
@@ -694,74 +821,35 @@ module ActiveRecord
694
821
  # # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
695
822
  # <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
696
823
  #
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
824
+ def collect_join_chain
825
+ collect_join_reflections [self]
705
826
  end
706
827
 
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
828
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
829
+ # SQL queries on associations.
830
+ def clear_association_scope_cache # :nodoc:
831
+ delegate_reflection.clear_association_scope_cache
832
+ source_reflection.clear_association_scope_cache
833
+ through_reflection.clear_association_scope_cache
746
834
  end
747
835
 
748
- def join_keys(assoc_klass)
749
- source_reflection.join_keys(assoc_klass)
836
+ def scopes
837
+ source_reflection.scopes + super
750
838
  end
751
839
 
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
840
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
841
+ source_reflection.join_scopes(table, predicate_builder, klass) + super
842
+ end
758
843
 
759
- source_reflection.source_macro
844
+ def has_scope?
845
+ scope || options[:source_type] ||
846
+ source_reflection.has_scope? ||
847
+ through_reflection.has_scope?
760
848
  end
761
849
 
762
850
  # A through association is nested if there would be more than one join table
763
851
  def nested?
764
- chain.length > 2
852
+ source_reflection.through_reflection? || through_reflection.through_reflection?
765
853
  end
766
854
 
767
855
  # We want to use the klass from this reflection, rather than just delegate straight to
@@ -791,21 +879,19 @@ module ActiveRecord
791
879
  def source_reflection_name # :nodoc:
792
880
  return @source_reflection_name if @source_reflection_name
793
881
 
794
- names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq
882
+ names = [name.to_s.singularize, name].collect(&:to_sym).uniq
795
883
  names = names.find_all { |n|
796
884
  through_reflection.klass._reflect_on_association(n)
797
885
  }
798
886
 
799
887
  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"
888
+ raise AmbiguousSourceReflectionForThroughAssociation.new(
889
+ active_record.name,
890
+ macro,
891
+ name,
892
+ options,
893
+ source_reflection_names
894
+ )
809
895
  end
810
896
 
811
897
  @source_reflection_name = names.first
@@ -819,10 +905,6 @@ module ActiveRecord
819
905
  through_reflection.options
820
906
  end
821
907
 
822
- def join_id_for(owner) # :nodoc:
823
- source_reflection.join_id_for(owner)
824
- end
825
-
826
908
  def check_validity!
827
909
  if through_reflection.nil?
828
910
  raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
@@ -852,20 +934,54 @@ module ActiveRecord
852
934
  raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
853
935
  end
854
936
 
937
+ if parent_reflection.nil?
938
+ reflections = active_record.reflections.keys.map(&:to_sym)
939
+
940
+ if reflections.index(through_reflection.name) > reflections.index(name)
941
+ raise HasManyThroughOrderError.new(active_record.name, self, through_reflection)
942
+ end
943
+ end
944
+
855
945
  check_validity_of_inverse!
856
946
  end
857
947
 
858
- protected
948
+ def constraints
949
+ scope_chain = source_reflection.constraints
950
+ scope_chain << scope if scope
951
+ scope_chain
952
+ end
859
953
 
954
+ def add_as_source(seed)
955
+ collect_join_reflections seed
956
+ end
957
+
958
+ def add_as_polymorphic_through(reflection, seed)
959
+ collect_join_reflections(seed + [PolymorphicReflection.new(self, reflection)])
960
+ end
961
+
962
+ def add_as_through(seed)
963
+ collect_join_reflections(seed + [self])
964
+ end
965
+
966
+ protected
860
967
  def actual_source_reflection # FIXME: this is a horrible name
861
- source_reflection.send(:actual_source_reflection)
968
+ source_reflection.actual_source_reflection
862
969
  end
863
970
 
864
- def primary_key(klass)
865
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
971
+ private
972
+ attr_reader :delegate_reflection
973
+
974
+ def collect_join_reflections(seed)
975
+ a = source_reflection.add_as_source seed
976
+ if options[:source_type]
977
+ through_reflection.add_as_polymorphic_through self, a
978
+ else
979
+ through_reflection.add_as_through a
980
+ end
866
981
  end
867
982
 
868
- private
983
+ def inverse_name; delegate_reflection.send(:inverse_name); end
984
+
869
985
  def derive_class_name
870
986
  # get the class_name of the belongs_to association of the through reflection
871
987
  options[:source_type] || source_reflection.class_name
@@ -875,7 +991,50 @@ module ActiveRecord
875
991
  public_instance_methods
876
992
 
877
993
  delegate(*delegate_methods, to: :delegate_reflection)
994
+ end
995
+
996
+ class PolymorphicReflection < AbstractReflection # :nodoc:
997
+ delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
998
+
999
+ def initialize(reflection, previous_reflection)
1000
+ @reflection = reflection
1001
+ @previous_reflection = previous_reflection
1002
+ end
1003
+
1004
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
1005
+ scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1006
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
1007
+ end
1008
+
1009
+ def constraints
1010
+ @reflection.constraints + [source_type_scope]
1011
+ end
1012
+
1013
+ private
1014
+ def source_type_scope
1015
+ type = @previous_reflection.foreign_type
1016
+ source_type = @previous_reflection.options[:source_type]
1017
+ lambda { |object| where(type => source_type) }
1018
+ end
1019
+ end
1020
+
1021
+ class RuntimeReflection < AbstractReflection # :nodoc:
1022
+ delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
1023
+
1024
+ def initialize(reflection, association)
1025
+ @reflection = reflection
1026
+ @association = association
1027
+ end
1028
+
1029
+ def klass
1030
+ @association.klass
1031
+ end
1032
+
1033
+ def aliased_table
1034
+ @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
1035
+ end
878
1036
 
1037
+ def all_includes; yield; end
879
1038
  end
880
1039
  end
881
1040
  end