activerecord 5.0.7.2 → 6.1.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 (363) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +829 -2015
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +11 -9
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -29
  8. data/lib/active_record/aggregations.rb +249 -247
  9. data/lib/active_record/association_relation.rb +30 -18
  10. data/lib/active_record/associations.rb +1714 -1596
  11. data/lib/active_record/associations/alias_tracker.rb +36 -42
  12. data/lib/active_record/associations/association.rb +143 -68
  13. data/lib/active_record/associations/association_scope.rb +98 -94
  14. data/lib/active_record/associations/belongs_to_association.rb +76 -46
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -28
  17. data/lib/active_record/associations/builder/belongs_to.rb +52 -60
  18. data/lib/active_record/associations/builder/collection_association.rb +12 -22
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
  20. data/lib/active_record/associations/builder/has_many.rb +10 -2
  21. data/lib/active_record/associations/builder/has_one.rb +35 -2
  22. data/lib/active_record/associations/builder/singular_association.rb +5 -1
  23. data/lib/active_record/associations/collection_association.rb +104 -259
  24. data/lib/active_record/associations/collection_proxy.rb +169 -125
  25. data/lib/active_record/associations/foreign_association.rb +22 -0
  26. data/lib/active_record/associations/has_many_association.rb +46 -31
  27. data/lib/active_record/associations/has_many_through_association.rb +66 -46
  28. data/lib/active_record/associations/has_one_association.rb +71 -52
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +169 -180
  31. data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +97 -104
  35. data/lib/active_record/associations/preloader/association.rb +109 -97
  36. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  37. data/lib/active_record/associations/singular_association.rb +12 -45
  38. data/lib/active_record/associations/through_association.rb +27 -15
  39. data/lib/active_record/attribute_assignment.rb +55 -60
  40. data/lib/active_record/attribute_methods.rb +111 -141
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
  42. data/lib/active_record/attribute_methods/dirty.rb +172 -112
  43. data/lib/active_record/attribute_methods/primary_key.rb +88 -91
  44. data/lib/active_record/attribute_methods/query.rb +6 -8
  45. data/lib/active_record/attribute_methods/read.rb +18 -50
  46. data/lib/active_record/attribute_methods/serialization.rb +38 -10
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
  48. data/lib/active_record/attribute_methods/write.rb +25 -32
  49. data/lib/active_record/attributes.rb +69 -31
  50. data/lib/active_record/autosave_association.rb +102 -66
  51. data/lib/active_record/base.rb +16 -25
  52. data/lib/active_record/callbacks.rb +202 -43
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -12
  55. data/lib/active_record/connection_adapters.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
  69. data/lib/active_record/connection_adapters/column.rb +55 -13
  70. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  71. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +79 -49
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -56
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +20 -12
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
  82. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  83. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
  85. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
  86. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  90. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -6
  93. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
  95. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  98. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  106. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
  107. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  109. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  110. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +98 -38
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +426 -324
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
  121. data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
  123. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  124. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -6
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +282 -290
  131. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  132. data/lib/active_record/connection_handling.rb +287 -45
  133. data/lib/active_record/core.rb +385 -181
  134. data/lib/active_record/counter_cache.rb +60 -28
  135. data/lib/active_record/database_configurations.rb +272 -0
  136. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  137. data/lib/active_record/database_configurations/database_config.rb +80 -0
  138. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  139. data/lib/active_record/database_configurations/url_config.rb +53 -0
  140. data/lib/active_record/delegated_type.rb +209 -0
  141. data/lib/active_record/destroy_association_async_job.rb +36 -0
  142. data/lib/active_record/dynamic_matchers.rb +87 -87
  143. data/lib/active_record/enum.rb +122 -47
  144. data/lib/active_record/errors.rb +153 -22
  145. data/lib/active_record/explain.rb +13 -8
  146. data/lib/active_record/explain_registry.rb +3 -1
  147. data/lib/active_record/explain_subscriber.rb +9 -4
  148. data/lib/active_record/fixture_set/file.rb +20 -22
  149. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  150. data/lib/active_record/fixture_set/render_context.rb +17 -0
  151. data/lib/active_record/fixture_set/table_row.rb +152 -0
  152. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  153. data/lib/active_record/fixtures.rb +246 -507
  154. data/lib/active_record/gem_version.rb +6 -4
  155. data/lib/active_record/inheritance.rb +168 -95
  156. data/lib/active_record/insert_all.rb +208 -0
  157. data/lib/active_record/integration.rb +114 -25
  158. data/lib/active_record/internal_metadata.rb +30 -24
  159. data/lib/active_record/legacy_yaml_adapter.rb +11 -5
  160. data/lib/active_record/locking/optimistic.rb +81 -85
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +68 -31
  163. data/lib/active_record/middleware/database_selector.rb +77 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  166. data/lib/active_record/migration.rb +439 -342
  167. data/lib/active_record/migration/command_recorder.rb +152 -98
  168. data/lib/active_record/migration/compatibility.rb +229 -60
  169. data/lib/active_record/migration/join_table.rb +8 -7
  170. data/lib/active_record/model_schema.rb +230 -122
  171. data/lib/active_record/nested_attributes.rb +213 -203
  172. data/lib/active_record/no_touching.rb +11 -2
  173. data/lib/active_record/null_relation.rb +12 -34
  174. data/lib/active_record/persistence.rb +471 -97
  175. data/lib/active_record/query_cache.rb +23 -12
  176. data/lib/active_record/querying.rb +43 -25
  177. data/lib/active_record/railtie.rb +155 -43
  178. data/lib/active_record/railties/console_sandbox.rb +2 -0
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +507 -195
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +245 -269
  183. data/lib/active_record/relation.rb +475 -324
  184. data/lib/active_record/relation/batches.rb +125 -72
  185. data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
  186. data/lib/active_record/relation/calculations.rb +267 -171
  187. data/lib/active_record/relation/delegation.rb +73 -69
  188. data/lib/active_record/relation/finder_methods.rb +238 -248
  189. data/lib/active_record/relation/from_clause.rb +7 -9
  190. data/lib/active_record/relation/merger.rb +95 -77
  191. data/lib/active_record/relation/predicate_builder.rb +109 -110
  192. data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
  193. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  194. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  195. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
  196. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  197. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  198. data/lib/active_record/relation/query_attribute.rb +33 -2
  199. data/lib/active_record/relation/query_methods.rb +654 -374
  200. data/lib/active_record/relation/record_fetch_warning.rb +8 -6
  201. data/lib/active_record/relation/spawn_methods.rb +15 -14
  202. data/lib/active_record/relation/where_clause.rb +171 -109
  203. data/lib/active_record/result.rb +88 -51
  204. data/lib/active_record/runtime_registry.rb +5 -3
  205. data/lib/active_record/sanitization.rb +73 -100
  206. data/lib/active_record/schema.rb +7 -14
  207. data/lib/active_record/schema_dumper.rb +101 -69
  208. data/lib/active_record/schema_migration.rb +16 -12
  209. data/lib/active_record/scoping.rb +20 -20
  210. data/lib/active_record/scoping/default.rb +92 -95
  211. data/lib/active_record/scoping/named.rb +39 -30
  212. data/lib/active_record/secure_token.rb +19 -9
  213. data/lib/active_record/serialization.rb +7 -3
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +80 -29
  216. data/lib/active_record/store.rb +122 -42
  217. data/lib/active_record/suppressor.rb +6 -3
  218. data/lib/active_record/table_metadata.rb +51 -39
  219. data/lib/active_record/tasks/database_tasks.rb +332 -115
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +246 -0
  225. data/lib/active_record/timestamp.rb +70 -38
  226. data/lib/active_record/touch_later.rb +26 -24
  227. data/lib/active_record/transactions.rb +121 -184
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type.rb +29 -17
  230. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  231. data/lib/active_record/type/date.rb +2 -0
  232. data/lib/active_record/type/date_time.rb +2 -0
  233. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  234. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  235. data/lib/active_record/type/internal/timezone.rb +2 -0
  236. data/lib/active_record/type/json.rb +30 -0
  237. data/lib/active_record/type/serialized.rb +20 -9
  238. data/lib/active_record/type/text.rb +11 -0
  239. data/lib/active_record/type/time.rb +12 -1
  240. data/lib/active_record/type/type_map.rb +14 -17
  241. data/lib/active_record/type/unsigned_integer.rb +16 -0
  242. data/lib/active_record/type_caster.rb +4 -2
  243. data/lib/active_record/type_caster/connection.rb +17 -13
  244. data/lib/active_record/type_caster/map.rb +10 -6
  245. data/lib/active_record/validations.rb +8 -5
  246. data/lib/active_record/validations/absence.rb +2 -0
  247. data/lib/active_record/validations/associated.rb +4 -3
  248. data/lib/active_record/validations/length.rb +2 -0
  249. data/lib/active_record/validations/numericality.rb +35 -0
  250. data/lib/active_record/validations/presence.rb +4 -2
  251. data/lib/active_record/validations/uniqueness.rb +52 -45
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/arel.rb +54 -0
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes.rb +70 -0
  269. data/lib/arel/nodes/and.rb +32 -0
  270. data/lib/arel/nodes/ascending.rb +23 -0
  271. data/lib/arel/nodes/binary.rb +126 -0
  272. data/lib/arel/nodes/bind_param.rb +44 -0
  273. data/lib/arel/nodes/case.rb +55 -0
  274. data/lib/arel/nodes/casted.rb +62 -0
  275. data/lib/arel/nodes/comment.rb +29 -0
  276. data/lib/arel/nodes/count.rb +12 -0
  277. data/lib/arel/nodes/delete_statement.rb +45 -0
  278. data/lib/arel/nodes/descending.rb +23 -0
  279. data/lib/arel/nodes/equality.rb +15 -0
  280. data/lib/arel/nodes/extract.rb +24 -0
  281. data/lib/arel/nodes/false.rb +16 -0
  282. data/lib/arel/nodes/full_outer_join.rb +8 -0
  283. data/lib/arel/nodes/function.rb +44 -0
  284. data/lib/arel/nodes/grouping.rb +11 -0
  285. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  286. data/lib/arel/nodes/in.rb +15 -0
  287. data/lib/arel/nodes/infix_operation.rb +92 -0
  288. data/lib/arel/nodes/inner_join.rb +8 -0
  289. data/lib/arel/nodes/insert_statement.rb +37 -0
  290. data/lib/arel/nodes/join_source.rb +20 -0
  291. data/lib/arel/nodes/matches.rb +18 -0
  292. data/lib/arel/nodes/named_function.rb +23 -0
  293. data/lib/arel/nodes/node.rb +51 -0
  294. data/lib/arel/nodes/node_expression.rb +13 -0
  295. data/lib/arel/nodes/ordering.rb +27 -0
  296. data/lib/arel/nodes/outer_join.rb +8 -0
  297. data/lib/arel/nodes/over.rb +15 -0
  298. data/lib/arel/nodes/regexp.rb +16 -0
  299. data/lib/arel/nodes/right_outer_join.rb +8 -0
  300. data/lib/arel/nodes/select_core.rb +67 -0
  301. data/lib/arel/nodes/select_statement.rb +41 -0
  302. data/lib/arel/nodes/sql_literal.rb +19 -0
  303. data/lib/arel/nodes/string_join.rb +11 -0
  304. data/lib/arel/nodes/table_alias.rb +31 -0
  305. data/lib/arel/nodes/terminal.rb +16 -0
  306. data/lib/arel/nodes/true.rb +16 -0
  307. data/lib/arel/nodes/unary.rb +44 -0
  308. data/lib/arel/nodes/unary_operation.rb +20 -0
  309. data/lib/arel/nodes/unqualified_column.rb +22 -0
  310. data/lib/arel/nodes/update_statement.rb +41 -0
  311. data/lib/arel/nodes/values_list.rb +9 -0
  312. data/lib/arel/nodes/window.rb +126 -0
  313. data/lib/arel/nodes/with.rb +11 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors.rb +13 -0
  321. data/lib/arel/visitors/dot.rb +308 -0
  322. data/lib/arel/visitors/mysql.rb +93 -0
  323. data/lib/arel/visitors/postgresql.rb +120 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +899 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/rails/generators/active_record.rb +7 -5
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration.rb +22 -3
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
  333. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
  334. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
  335. data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. metadata +141 -57
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute.rb +0 -213
  348. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  349. data/lib/active_record/attribute_decorators.rb +0 -67
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
  355. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
  356. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  359. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -17
  360. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  361. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  362. data/lib/active_record/relation/where_clause_factory.rb +0 -38
  363. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,22 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ReadonlyAttributes
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  included do
6
- class_attribute :_attr_readonly, instance_accessor: false
7
- self._attr_readonly = []
8
+ class_attribute :_attr_readonly, instance_accessor: false, default: []
8
9
  end
9
10
 
10
11
  module ClassMethods
11
12
  # Attributes listed as readonly will be used to create a new record but update operations will
12
13
  # ignore these fields.
13
14
  def attr_readonly(*attributes)
14
- self._attr_readonly = Set.new(attributes.map(&:to_s)) + (self._attr_readonly || [])
15
+ self._attr_readonly = Set.new(attributes.map(&:to_s)) + (_attr_readonly || [])
15
16
  end
16
17
 
17
18
  # Returns an array of all the attributes that have been specified as readonly.
18
19
  def readonly_attributes
19
- self._attr_readonly
20
+ _attr_readonly
21
+ end
22
+
23
+ def readonly_attribute?(name) # :nodoc:
24
+ _attr_readonly.include?(name)
20
25
  end
21
26
  end
22
27
  end
@@ -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,37 +8,41 @@ module ActiveRecord
7
8
  extend ActiveSupport::Concern
8
9
 
9
10
  included do
10
- class_attribute :_reflections, instance_writer: false
11
- class_attribute :aggregate_reflections, instance_writer: false
12
- self._reflections = {}
13
- self.aggregate_reflections = {}
11
+ class_attribute :_reflections, instance_writer: false, default: {}
12
+ class_attribute :aggregate_reflections, instance_writer: false, default: {}
14
13
  end
15
14
 
16
- def self.create(macro, name, scope, options, ar)
17
- klass = case macro
18
- when :composed_of
19
- AggregateReflection
20
- when :has_many
21
- HasManyReflection
22
- when :has_one
23
- HasOneReflection
24
- when :belongs_to
25
- BelongsToReflection
26
- else
27
- raise "Unsupported Macro: #{macro}"
28
- end
29
-
30
- reflection = klass.new(name, scope, options, ar)
31
- options[:through] ? ThroughReflection.new(reflection) : reflection
32
- end
15
+ class << self
16
+ def create(macro, name, scope, options, ar)
17
+ reflection = reflection_class_for(macro).new(name, scope, options, ar)
18
+ options[:through] ? ThroughReflection.new(reflection) : reflection
19
+ end
33
20
 
34
- def self.add_reflection(ar, name, reflection)
35
- ar.clear_reflections_cache
36
- ar._reflections = ar._reflections.merge(name.to_s => reflection)
37
- end
21
+ def add_reflection(ar, name, reflection)
22
+ ar.clear_reflections_cache
23
+ name = -name.to_s
24
+ ar._reflections = ar._reflections.except(name).merge!(name => reflection)
25
+ end
26
+
27
+ def add_aggregate_reflection(ar, name, reflection)
28
+ ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
29
+ end
38
30
 
39
- def self.add_aggregate_reflection(ar, name, reflection)
40
- ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
31
+ private
32
+ def reflection_class_for(macro)
33
+ case macro
34
+ when :composed_of
35
+ AggregateReflection
36
+ when :has_many
37
+ HasManyReflection
38
+ when :has_one
39
+ HasOneReflection
40
+ when :belongs_to
41
+ BelongsToReflection
42
+ else
43
+ raise "Unsupported Macro: #{macro}"
44
+ end
45
+ end
41
46
  end
42
47
 
43
48
  # \Reflection enables the ability to examine the associations and aggregations of
@@ -135,8 +140,8 @@ module ActiveRecord
135
140
  # BelongsToReflection
136
141
  # HasAndBelongsToManyReflection
137
142
  # ThroughReflection
138
- # PolymorphicReflection
139
- # RuntimeReflection
143
+ # PolymorphicReflection
144
+ # RuntimeReflection
140
145
  class AbstractReflection # :nodoc:
141
146
  def through_reflection?
142
147
  false
@@ -152,41 +157,69 @@ module ActiveRecord
152
157
  klass.new(attributes, &block)
153
158
  end
154
159
 
155
- def quoted_table_name
156
- klass.quoted_table_name
157
- end
158
-
159
- def primary_key_type
160
- klass.type_for_attribute(klass.primary_key)
161
- end
162
-
163
160
  # Returns the class name for the macro.
164
161
  #
165
162
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
166
163
  # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
167
164
  def class_name
168
- @class_name ||= (options[:class_name] || derive_class_name).to_s
165
+ @class_name ||= -(options[:class_name]&.to_s || derive_class_name)
169
166
  end
170
167
 
171
- JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
168
+ # Returns a list of scopes that should be applied for this Reflection
169
+ # object when querying the database.
170
+ def scopes
171
+ scope ? [scope] : []
172
+ end
173
+
174
+ def join_scope(table, foreign_table, foreign_klass)
175
+ predicate_builder = predicate_builder(table)
176
+ scope_chain_items = join_scopes(table, predicate_builder)
177
+ klass_scope = klass_join_scope(table, predicate_builder)
172
178
 
173
- def join_keys(association_klass)
174
- JoinKeys.new(foreign_key, active_record_primary_key)
179
+ if type
180
+ klass_scope.where!(type => foreign_klass.polymorphic_name)
181
+ end
182
+
183
+ scope_chain_items.inject(klass_scope, &:merge!)
184
+
185
+ primary_key = join_primary_key
186
+ foreign_key = join_foreign_key
187
+
188
+ klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
189
+
190
+ if klass.finder_needs_type_condition?
191
+ klass_scope.where!(klass.send(:type_condition, table))
192
+ end
193
+
194
+ klass_scope
195
+ end
196
+
197
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
198
+ if scope
199
+ [scope_for(build_scope(table, predicate_builder, klass))]
200
+ else
201
+ []
202
+ end
203
+ end
204
+
205
+ def klass_join_scope(table, predicate_builder) # :nodoc:
206
+ relation = build_scope(table, predicate_builder)
207
+ klass.scope_for_association(relation)
175
208
  end
176
209
 
177
210
  def constraints
178
- scope_chain.flatten
211
+ chain.flat_map(&:scopes)
179
212
  end
180
213
 
181
214
  def counter_cache_column
182
- if belongs_to?
215
+ @counter_cache_column ||= if belongs_to?
183
216
  if options[:counter_cache] == true
184
- "#{active_record.name.demodulize.underscore.pluralize}_count"
217
+ -"#{active_record.name.demodulize.underscore.pluralize}_count"
185
218
  elsif options[:counter_cache]
186
- options[:counter_cache].to_s
219
+ -options[:counter_cache].to_s
187
220
  end
188
221
  else
189
- options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
222
+ -(options[:counter_cache]&.to_s || "#{name}_count")
190
223
  end
191
224
  end
192
225
 
@@ -233,7 +266,7 @@ module ActiveRecord
233
266
  def has_cached_counter?
234
267
  options[:counter_cache] ||
235
268
  inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
236
- !!active_record.columns_hash[counter_cache_column]
269
+ active_record.has_attribute?(counter_cache_column)
237
270
  end
238
271
 
239
272
  def counter_must_be_updated_by_has_many?
@@ -247,6 +280,32 @@ module ActiveRecord
247
280
  def chain
248
281
  collect_join_chain
249
282
  end
283
+
284
+ def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
285
+ Relation.create(
286
+ klass,
287
+ table: table,
288
+ predicate_builder: predicate_builder
289
+ )
290
+ end
291
+
292
+ def strict_loading?
293
+ options[:strict_loading]
294
+ end
295
+
296
+ protected
297
+ def actual_source_reflection # FIXME: this is a horrible name
298
+ self
299
+ end
300
+
301
+ private
302
+ def predicate_builder(table)
303
+ PredicateBuilder.new(TableMetadata.new(klass, table))
304
+ end
305
+
306
+ def primary_key(klass)
307
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
308
+ end
250
309
  end
251
310
 
252
311
  # Base class for AggregateReflection and AssociationReflection. Objects of
@@ -281,7 +340,6 @@ module ActiveRecord
281
340
  end
282
341
 
283
342
  def autosave=(autosave)
284
- @automatic_inverse_of = false
285
343
  @options[:autosave] = autosave
286
344
  parent_reflection = self.parent_reflection
287
345
  if parent_reflection
@@ -293,6 +351,17 @@ module ActiveRecord
293
351
  #
294
352
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
295
353
  # <tt>has_many :clients</tt> returns the Client class
354
+ #
355
+ # class Company < ActiveRecord::Base
356
+ # has_many :clients
357
+ # end
358
+ #
359
+ # Company.reflect_on_association(:clients).klass
360
+ # # => Client
361
+ #
362
+ # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
363
+ # a new association object. Use +build_association+ or +create_association+
364
+ # instead. This allows plugins to hook into association object creation.
296
365
  def klass
297
366
  @klass ||= compute_class(class_name)
298
367
  end
@@ -311,8 +380,8 @@ module ActiveRecord
311
380
  active_record == other_aggregation.active_record
312
381
  end
313
382
 
314
- def scope_for(klass)
315
- scope ? klass.unscoped.instance_exec(nil, &scope) : klass.unscoped
383
+ def scope_for(relation, owner = nil)
384
+ relation.instance_exec(owner, &scope) || relation
316
385
  end
317
386
 
318
387
  private
@@ -321,8 +390,7 @@ module ActiveRecord
321
390
  end
322
391
  end
323
392
 
324
-
325
- # Holds all the meta-data about an aggregation as it was specified in the
393
+ # Holds all the metadata about an aggregation as it was specified in the
326
394
  # Active Record class.
327
395
  class AggregateReflection < MacroReflection #:nodoc:
328
396
  def mapping
@@ -331,26 +399,13 @@ module ActiveRecord
331
399
  end
332
400
  end
333
401
 
334
- # Holds all the meta-data about an association as it was specified in the
402
+ # Holds all the metadata about an association as it was specified in the
335
403
  # Active Record class.
336
404
  class AssociationReflection < MacroReflection #:nodoc:
337
- # Returns the target association's class.
338
- #
339
- # class Author < ActiveRecord::Base
340
- # has_many :books
341
- # end
342
- #
343
- # Author.reflect_on_association(:books).klass
344
- # # => Book
345
- #
346
- # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
347
- # a new association object. Use +build_association+ or +create_association+
348
- # instead. This allows plugins to hook into association object creation.
349
- def klass
350
- @klass ||= compute_class(class_name)
351
- end
352
-
353
405
  def compute_class(name)
406
+ if polymorphic?
407
+ raise ArgumentError, "Polymorphic associations do not support computing the class."
408
+ end
354
409
  active_record.send(:compute_type, name)
355
410
  end
356
411
 
@@ -359,22 +414,21 @@ module ActiveRecord
359
414
 
360
415
  def initialize(name, scope, options, active_record)
361
416
  super
362
- @automatic_inverse_of = nil
363
- @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
364
- @foreign_type = options[:foreign_type] || "#{name}_type"
417
+ @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
418
+ @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
365
419
  @constructable = calculate_constructable(macro, options)
366
- @association_scope_cache = {}
367
- @scope_lock = Mutex.new
420
+
421
+ if options[:class_name] && options[:class_name].class == Class
422
+ raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
423
+ end
368
424
  end
369
425
 
370
- def association_scope_cache(conn, owner)
371
- key = conn.prepared_statements
426
+ def association_scope_cache(klass, owner, &block)
427
+ key = self
372
428
  if polymorphic?
373
429
  key = [key, owner._read_attribute(@foreign_type)]
374
430
  end
375
- @association_scope_cache[key] ||= @scope_lock.synchronize {
376
- @association_scope_cache[key] ||= yield
377
- }
431
+ klass.cached_find_by_statement(key, &block)
378
432
  end
379
433
 
380
434
  def constructable? # :nodoc:
@@ -382,28 +436,31 @@ module ActiveRecord
382
436
  end
383
437
 
384
438
  def join_table
385
- @join_table ||= options[:join_table] || derive_join_table
439
+ @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
386
440
  end
387
441
 
388
442
  def foreign_key
389
- @foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
443
+ @foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
390
444
  end
391
445
 
392
446
  def association_foreign_key
393
- @association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
447
+ @association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
394
448
  end
395
449
 
396
- # klass option is necessary to support loading polymorphic associations
397
450
  def association_primary_key(klass = nil)
398
- options[:primary_key] || primary_key(klass || self.klass)
451
+ primary_key(klass || self.klass)
399
452
  end
400
453
 
401
- def association_primary_key_type
402
- klass.type_for_attribute(association_primary_key.to_s)
454
+ def active_record_primary_key
455
+ @active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
403
456
  end
404
457
 
405
- def active_record_primary_key
406
- @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
458
+ def join_primary_key(klass = nil)
459
+ foreign_key
460
+ end
461
+
462
+ def join_foreign_key
463
+ active_record_primary_key
407
464
  end
408
465
 
409
466
  def check_validity!
@@ -413,7 +470,7 @@ module ActiveRecord
413
470
  def check_preloadable!
414
471
  return unless scope
415
472
 
416
- if scope.arity > 0
473
+ unless scope.arity == 0
417
474
  raise ArgumentError, <<-MSG.squish
418
475
  The association scope '#{name}' is instance dependent (the scope
419
476
  block takes an argument). Preloading instance dependent scopes is
@@ -424,7 +481,7 @@ module ActiveRecord
424
481
  alias :check_eager_loadable! :check_preloadable!
425
482
 
426
483
  def join_id_for(owner) # :nodoc:
427
- owner[active_record_primary_key]
484
+ owner[join_foreign_key]
428
485
  end
429
486
 
430
487
  def through_reflection
@@ -444,19 +501,13 @@ module ActiveRecord
444
501
  # This is for clearing cache on the reflection. Useful for tests that need to compare
445
502
  # SQL queries on associations.
446
503
  def clear_association_scope_cache # :nodoc:
447
- @association_scope_cache.clear
504
+ klass.initialize_find_by_cache
448
505
  end
449
506
 
450
507
  def nested?
451
508
  false
452
509
  end
453
510
 
454
- # An array of arrays of scopes. Each item in the outside array corresponds to a reflection
455
- # in the #chain.
456
- def scope_chain
457
- scope ? [[scope]] : [[]]
458
- end
459
-
460
511
  def has_scope?
461
512
  scope
462
513
  end
@@ -513,7 +564,7 @@ module ActiveRecord
513
564
  end
514
565
 
515
566
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
516
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
567
+ INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
517
568
 
518
569
  def add_as_source(seed)
519
570
  seed
@@ -531,32 +582,23 @@ module ActiveRecord
531
582
  Array(options[:extend])
532
583
  end
533
584
 
534
- protected
535
-
536
- def actual_source_reflection # FIXME: this is a horrible name
537
- self
538
- end
539
-
540
585
  private
541
-
542
586
  def calculate_constructable(macro, options)
543
587
  true
544
588
  end
545
589
 
546
590
  # Attempts to find the inverse association name automatically.
547
591
  # If it cannot find a suitable inverse association name, it returns
548
- # nil.
592
+ # +nil+.
549
593
  def inverse_name
550
- options.fetch(:inverse_of) do
551
- if @automatic_inverse_of == false
552
- nil
553
- else
554
- @automatic_inverse_of ||= automatic_inverse_of
555
- end
594
+ unless defined?(@inverse_name)
595
+ @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
556
596
  end
597
+
598
+ @inverse_name
557
599
  end
558
600
 
559
- # returns either false or the inverse association name that it finds.
601
+ # returns either +nil+ or the inverse association name that it finds.
560
602
  def automatic_inverse_of
561
603
  if can_find_inverse_of_automatically?(self)
562
604
  inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
@@ -570,23 +612,19 @@ module ActiveRecord
570
612
  end
571
613
 
572
614
  if valid_inverse_reflection?(reflection)
573
- return inverse_name
615
+ inverse_name
574
616
  end
575
617
  end
576
-
577
- false
578
618
  end
579
619
 
580
620
  # Checks if the inverse reflection that is returned from the
581
621
  # +automatic_inverse_of+ method is a valid reflection. We must
582
622
  # make sure that the reflection's active_record name matches up
583
623
  # with the current reflection's klass name.
584
- #
585
- # Note: klass will always be valid because when there's a NameError
586
- # from calling +klass+, +reflection+ will already be set to false.
587
624
  def valid_inverse_reflection?(reflection)
588
625
  reflection &&
589
- klass.name == reflection.active_record.name &&
626
+ foreign_key == reflection.foreign_key &&
627
+ klass <= reflection.active_record &&
590
628
  can_find_inverse_of_automatically?(reflection)
591
629
  end
592
630
 
@@ -594,9 +632,8 @@ module ActiveRecord
594
632
  # us from being able to guess the inverse automatically. First, the
595
633
  # <tt>inverse_of</tt> option cannot be set to false. Second, we must
596
634
  # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
597
- # Third, we must not have options such as <tt>:polymorphic</tt> or
598
- # <tt>:foreign_key</tt> which prevent us from correctly guessing the
599
- # inverse association.
635
+ # Third, we must not have options such as <tt>:foreign_key</tt>
636
+ # which prevent us from correctly guessing the inverse association.
600
637
  #
601
638
  # Anything with a scope can additionally ruin our attempt at finding an
602
639
  # inverse, so we exclude reflections with scopes.
@@ -626,10 +663,6 @@ module ActiveRecord
626
663
  def derive_join_table
627
664
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
628
665
  end
629
-
630
- def primary_key(klass)
631
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
632
- end
633
666
  end
634
667
 
635
668
  class HasManyReflection < AssociationReflection # :nodoc:
@@ -644,10 +677,6 @@ module ActiveRecord
644
677
  Associations::HasManyAssociation
645
678
  end
646
679
  end
647
-
648
- def association_primary_key(klass = nil)
649
- primary_key(klass || self.klass)
650
- end
651
680
  end
652
681
 
653
682
  class HasOneReflection < AssociationReflection # :nodoc:
@@ -664,7 +693,6 @@ module ActiveRecord
664
693
  end
665
694
 
666
695
  private
667
-
668
696
  def calculate_constructable(macro, options)
669
697
  !options[:through]
670
698
  end
@@ -683,16 +711,31 @@ module ActiveRecord
683
711
  end
684
712
  end
685
713
 
686
- def join_keys(association_klass)
687
- key = polymorphic? ? association_primary_key(association_klass) : association_primary_key
688
- JoinKeys.new(key, foreign_key)
714
+ # klass option is necessary to support loading polymorphic associations
715
+ def association_primary_key(klass = nil)
716
+ if primary_key = options[:primary_key]
717
+ @association_primary_key ||= -primary_key.to_s
718
+ else
719
+ primary_key(klass || self.klass)
720
+ end
689
721
  end
690
722
 
691
- def join_id_for(owner) # :nodoc:
692
- owner[foreign_key]
723
+ def join_primary_key(klass = nil)
724
+ polymorphic? ? association_primary_key(klass) : association_primary_key
725
+ end
726
+
727
+ def join_foreign_key
728
+ foreign_key
729
+ end
730
+
731
+ def join_foreign_type
732
+ foreign_type
693
733
  end
694
734
 
695
735
  private
736
+ def can_find_inverse_of_automatically?(_)
737
+ !polymorphic? && super
738
+ end
696
739
 
697
740
  def calculate_constructable(macro, options)
698
741
  !polymorphic?
@@ -700,10 +743,6 @@ module ActiveRecord
700
743
  end
701
744
 
702
745
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
703
- def initialize(name, scope, options, active_record)
704
- super
705
- end
706
-
707
746
  def macro; :has_and_belongs_to_many; end
708
747
 
709
748
  def collection?
@@ -711,16 +750,15 @@ module ActiveRecord
711
750
  end
712
751
  end
713
752
 
714
- # Holds all the meta-data about a :through association as it was specified
753
+ # Holds all the metadata about a :through association as it was specified
715
754
  # in the Active Record class.
716
755
  class ThroughReflection < AbstractReflection #:nodoc:
717
- attr_reader :delegate_reflection
718
- delegate :foreign_key, :foreign_type, :association_foreign_key,
719
- :active_record_primary_key, :type, :to => :source_reflection
756
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
757
+ :active_record_primary_key, :join_foreign_key, to: :source_reflection
720
758
 
721
759
  def initialize(delegate_reflection)
722
760
  @delegate_reflection = delegate_reflection
723
- @klass = delegate_reflection.options[:anonymous_class]
761
+ @klass = delegate_reflection.options[:anonymous_class]
724
762
  @source_reflection_name = delegate_reflection.options[:source]
725
763
  end
726
764
 
@@ -798,45 +836,12 @@ module ActiveRecord
798
836
  through_reflection.clear_association_scope_cache
799
837
  end
800
838
 
801
- # Consider the following example:
802
- #
803
- # class Person
804
- # has_many :articles
805
- # has_many :comment_tags, through: :articles
806
- # end
807
- #
808
- # class Article
809
- # has_many :comments
810
- # has_many :comment_tags, through: :comments, source: :tags
811
- # end
812
- #
813
- # class Comment
814
- # has_many :tags
815
- # end
816
- #
817
- # There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags,
818
- # but only Comment.tags will be represented in the #chain. So this method creates an array
819
- # of scopes corresponding to the chain.
820
- def scope_chain
821
- @scope_chain ||= begin
822
- scope_chain = source_reflection.scope_chain.map(&:dup)
823
-
824
- # Add to it the scope from this reflection (if any)
825
- scope_chain.first << scope if scope
826
-
827
- through_scope_chain = through_reflection.scope_chain.map(&:dup)
828
-
829
- if options[:source_type]
830
- type = foreign_type
831
- source_type = options[:source_type]
832
- through_scope_chain.first << lambda { |object|
833
- where(type => source_type)
834
- }
835
- end
839
+ def scopes
840
+ source_reflection.scopes + super
841
+ end
836
842
 
837
- # Recursively fill out the rest of the array from the through reflection
838
- scope_chain + through_scope_chain
839
- end
843
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
844
+ source_reflection.join_scopes(table, predicate_builder, klass) + super
840
845
  end
841
846
 
842
847
  def has_scope?
@@ -845,10 +850,6 @@ module ActiveRecord
845
850
  through_reflection.has_scope?
846
851
  end
847
852
 
848
- def join_keys(association_klass)
849
- source_reflection.join_keys(association_klass)
850
- end
851
-
852
853
  # A through association is nested if there would be more than one join table
853
854
  def nested?
854
855
  source_reflection.through_reflection? || through_reflection.through_reflection?
@@ -860,11 +861,15 @@ module ActiveRecord
860
861
  def association_primary_key(klass = nil)
861
862
  # Get the "actual" source reflection if the immediate source reflection has a
862
863
  # source reflection itself
863
- actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
864
+ if primary_key = actual_source_reflection.options[:primary_key]
865
+ @association_primary_key ||= -primary_key.to_s
866
+ else
867
+ primary_key(klass || self.klass)
868
+ end
864
869
  end
865
870
 
866
- def association_primary_key_type
867
- klass.type_for_attribute(association_primary_key.to_s)
871
+ def join_primary_key(klass = self.klass)
872
+ source_reflection.join_primary_key(klass)
868
873
  end
869
874
 
870
875
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
@@ -891,15 +896,13 @@ module ActiveRecord
891
896
  }
892
897
 
893
898
  if names.length > 1
894
- example_options = options.dup
895
- example_options[:source] = source_reflection_names.first
896
- ActiveSupport::Deprecation.warn \
897
- "Ambiguous source reflection for through association. Please " \
898
- "specify a :source directive on your declaration like:\n" \
899
- "\n" \
900
- " class #{active_record.name} < ActiveRecord::Base\n" \
901
- " #{macro} :#{name}, #{example_options}\n" \
902
- " end"
899
+ raise AmbiguousSourceReflectionForThroughAssociation.new(
900
+ active_record.name,
901
+ macro,
902
+ name,
903
+ options,
904
+ source_reflection_names
905
+ )
903
906
  end
904
907
 
905
908
  @source_reflection_name = names.first
@@ -913,13 +916,9 @@ module ActiveRecord
913
916
  through_reflection.options
914
917
  end
915
918
 
916
- def join_id_for(owner) # :nodoc:
917
- source_reflection.join_id_for(owner)
918
- end
919
-
920
919
  def check_validity!
921
920
  if through_reflection.nil?
922
- raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
921
+ raise HasManyThroughAssociationNotFoundError.new(active_record, self)
923
922
  end
924
923
 
925
924
  if through_reflection.polymorphic?
@@ -946,6 +945,14 @@ module ActiveRecord
946
945
  raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
947
946
  end
948
947
 
948
+ if parent_reflection.nil?
949
+ reflections = active_record.reflections.keys.map(&:to_sym)
950
+
951
+ if reflections.index(through_reflection.name) > reflections.index(name)
952
+ raise HasManyThroughOrderError.new(active_record.name, self, through_reflection)
953
+ end
954
+ end
955
+
949
956
  check_validity_of_inverse!
950
957
  end
951
958
 
@@ -967,28 +974,25 @@ module ActiveRecord
967
974
  collect_join_reflections(seed + [self])
968
975
  end
969
976
 
970
- def collect_join_reflections(seed)
971
- a = source_reflection.add_as_source seed
972
- if options[:source_type]
973
- through_reflection.add_as_polymorphic_through self, a
974
- else
975
- through_reflection.add_as_through a
976
- end
977
- end
978
-
979
977
  protected
980
-
981
978
  def actual_source_reflection # FIXME: this is a horrible name
982
- source_reflection.send(:actual_source_reflection)
979
+ source_reflection.actual_source_reflection
983
980
  end
984
981
 
985
- def primary_key(klass)
986
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
982
+ private
983
+ attr_reader :delegate_reflection
984
+
985
+ def collect_join_reflections(seed)
986
+ a = source_reflection.add_as_source seed
987
+ if options[:source_type]
988
+ through_reflection.add_as_polymorphic_through self, a
989
+ else
990
+ through_reflection.add_as_through a
991
+ end
987
992
  end
988
993
 
989
994
  def inverse_name; delegate_reflection.send(:inverse_name); end
990
995
 
991
- private
992
996
  def derive_class_name
993
997
  # get the class_name of the belongs_to association of the through reflection
994
998
  options[:source_type] || source_reflection.class_name
@@ -998,52 +1002,36 @@ module ActiveRecord
998
1002
  public_instance_methods
999
1003
 
1000
1004
  delegate(*delegate_methods, to: :delegate_reflection)
1001
-
1002
1005
  end
1003
1006
 
1004
- class PolymorphicReflection < ThroughReflection # :nodoc:
1007
+ class PolymorphicReflection < AbstractReflection # :nodoc:
1008
+ delegate :klass, :scope, :plural_name, :type, :join_primary_key, :join_foreign_key,
1009
+ :name, :scope_for, to: :@reflection
1010
+
1005
1011
  def initialize(reflection, previous_reflection)
1006
1012
  @reflection = reflection
1007
1013
  @previous_reflection = previous_reflection
1008
1014
  end
1009
1015
 
1010
- def klass
1011
- @reflection.klass
1012
- end
1013
-
1014
- def scope
1015
- @reflection.scope
1016
- end
1017
-
1018
- def table_name
1019
- @reflection.table_name
1020
- end
1021
-
1022
- def plural_name
1023
- @reflection.plural_name
1024
- end
1025
-
1026
- def join_keys(association_klass)
1027
- @reflection.join_keys(association_klass)
1028
- end
1029
-
1030
- def type
1031
- @reflection.type
1016
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
1017
+ scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1018
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
1032
1019
  end
1033
1020
 
1034
1021
  def constraints
1035
- @reflection.constraints + [source_type_info]
1022
+ @reflection.constraints + [source_type_scope]
1036
1023
  end
1037
1024
 
1038
- def source_type_info
1039
- type = @previous_reflection.foreign_type
1040
- source_type = @previous_reflection.options[:source_type]
1041
- lambda { |object| where(type => source_type) }
1042
- end
1025
+ private
1026
+ def source_type_scope
1027
+ type = @previous_reflection.foreign_type
1028
+ source_type = @previous_reflection.options[:source_type]
1029
+ lambda { |object| where(type => source_type) }
1030
+ end
1043
1031
  end
1044
1032
 
1045
- class RuntimeReflection < PolymorphicReflection # :nodoc:
1046
- attr_accessor :next
1033
+ class RuntimeReflection < AbstractReflection # :nodoc:
1034
+ delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
1047
1035
 
1048
1036
  def initialize(reflection, association)
1049
1037
  @reflection = reflection
@@ -1054,24 +1042,12 @@ module ActiveRecord
1054
1042
  @association.klass
1055
1043
  end
1056
1044
 
1057
- def table_name
1058
- klass.table_name
1059
- end
1060
-
1061
- def constraints
1062
- @reflection.constraints
1063
- end
1064
-
1065
- def source_type_info
1066
- @reflection.source_type_info
1067
- end
1068
-
1069
- def alias_candidate(name)
1070
- "#{plural_name}_#{name}_join"
1045
+ def aliased_table
1046
+ klass.arel_table
1071
1047
  end
1072
1048
 
1073
- def alias_name
1074
- Arel::Table.new(table_name)
1049
+ def join_primary_key(klass = self.klass)
1050
+ @reflection.join_primary_key(klass)
1075
1051
  end
1076
1052
 
1077
1053
  def all_includes; yield; end