activerecord 4.2.11.3 → 6.0.2.2

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

Potentially problematic release.


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

Files changed (372) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +675 -1587
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +13 -12
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record.rb +41 -22
  8. data/lib/active_record/aggregations.rb +267 -251
  9. data/lib/active_record/association_relation.rb +26 -12
  10. data/lib/active_record/associations.rb +1737 -1597
  11. data/lib/active_record/associations/alias_tracker.rb +29 -35
  12. data/lib/active_record/associations/association.rb +133 -58
  13. data/lib/active_record/associations/association_scope.rb +103 -132
  14. data/lib/active_record/associations/belongs_to_association.rb +65 -60
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -40
  17. data/lib/active_record/associations/builder/belongs_to.rb +69 -55
  18. data/lib/active_record/associations/builder/collection_association.rb +10 -33
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +52 -66
  20. data/lib/active_record/associations/builder/has_many.rb +8 -4
  21. data/lib/active_record/associations/builder/has_one.rb +46 -5
  22. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  23. data/lib/active_record/associations/collection_association.rb +136 -288
  24. data/lib/active_record/associations/collection_proxy.rb +241 -146
  25. data/lib/active_record/associations/foreign_association.rb +10 -1
  26. data/lib/active_record/associations/has_many_association.rb +34 -97
  27. data/lib/active_record/associations/has_many_through_association.rb +60 -87
  28. data/lib/active_record/associations/has_one_association.rb +61 -49
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +141 -167
  31. data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +90 -92
  35. data/lib/active_record/associations/preloader/association.rb +90 -123
  36. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  37. data/lib/active_record/associations/singular_association.rb +18 -39
  38. data/lib/active_record/associations/through_association.rb +38 -18
  39. data/lib/active_record/attribute_assignment.rb +56 -183
  40. data/lib/active_record/attribute_decorators.rb +39 -15
  41. data/lib/active_record/attribute_methods.rb +120 -135
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -8
  43. data/lib/active_record/attribute_methods/dirty.rb +174 -144
  44. data/lib/active_record/attribute_methods/primary_key.rb +91 -83
  45. data/lib/active_record/attribute_methods/query.rb +6 -5
  46. data/lib/active_record/attribute_methods/read.rb +20 -76
  47. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
  49. data/lib/active_record/attribute_methods/write.rb +32 -54
  50. data/lib/active_record/attributes.rb +214 -82
  51. data/lib/active_record/autosave_association.rb +96 -38
  52. data/lib/active_record/base.rb +57 -45
  53. data/lib/active_record/callbacks.rb +100 -74
  54. data/lib/active_record/coders/json.rb +3 -1
  55. data/lib/active_record/coders/yaml_column.rb +24 -12
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +806 -296
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +238 -115
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -23
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +356 -227
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +664 -243
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -83
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +469 -202
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +517 -633
  69. data/lib/active_record/connection_adapters/column.rb +56 -43
  70. data/lib/active_record/connection_adapters/connection_specification.rb +174 -152
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +202 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +58 -180
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +66 -114
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  96. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  102. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  103. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +10 -5
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +470 -290
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +555 -356
  117. data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -345
  127. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  128. data/lib/active_record/connection_handling.rb +183 -41
  129. data/lib/active_record/core.rb +253 -229
  130. data/lib/active_record/counter_cache.rb +67 -49
  131. data/lib/active_record/database_configurations.rb +233 -0
  132. data/lib/active_record/database_configurations/database_config.rb +37 -0
  133. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  134. data/lib/active_record/database_configurations/url_config.rb +79 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +87 -105
  137. data/lib/active_record/enum.rb +163 -86
  138. data/lib/active_record/errors.rb +188 -53
  139. data/lib/active_record/explain.rb +23 -11
  140. data/lib/active_record/explain_registry.rb +4 -2
  141. data/lib/active_record/explain_subscriber.rb +10 -5
  142. data/lib/active_record/fixture_set/file.rb +35 -9
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +153 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  147. data/lib/active_record/fixtures.rb +228 -499
  148. data/lib/active_record/gem_version.rb +6 -4
  149. data/lib/active_record/inheritance.rb +158 -112
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +123 -29
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +21 -3
  154. data/lib/active_record/locale/en.yml +3 -2
  155. data/lib/active_record/locking/optimistic.rb +87 -96
  156. data/lib/active_record/locking/pessimistic.rb +18 -6
  157. data/lib/active_record/log_subscriber.rb +76 -33
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +621 -303
  162. data/lib/active_record/migration/command_recorder.rb +177 -90
  163. data/lib/active_record/migration/compatibility.rb +244 -0
  164. data/lib/active_record/migration/join_table.rb +8 -6
  165. data/lib/active_record/model_schema.rb +315 -112
  166. data/lib/active_record/nested_attributes.rb +264 -222
  167. data/lib/active_record/no_touching.rb +14 -1
  168. data/lib/active_record/null_relation.rb +24 -37
  169. data/lib/active_record/persistence.rb +557 -125
  170. data/lib/active_record/query_cache.rb +19 -23
  171. data/lib/active_record/querying.rb +43 -29
  172. data/lib/active_record/railtie.rb +143 -44
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +2 -0
  175. data/lib/active_record/railties/controller_runtime.rb +34 -33
  176. data/lib/active_record/railties/databases.rake +331 -185
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +428 -279
  179. data/lib/active_record/relation.rb +519 -341
  180. data/lib/active_record/relation/batches.rb +207 -55
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  182. data/lib/active_record/relation/calculations.rb +267 -253
  183. data/lib/active_record/relation/delegation.rb +70 -80
  184. data/lib/active_record/relation/finder_methods.rb +286 -241
  185. data/lib/active_record/relation/from_clause.rb +26 -0
  186. data/lib/active_record/relation/merger.rb +78 -87
  187. data/lib/active_record/relation/predicate_builder.rb +114 -119
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  195. data/lib/active_record/relation/query_attribute.rb +50 -0
  196. data/lib/active_record/relation/query_methods.rb +597 -393
  197. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  198. data/lib/active_record/relation/spawn_methods.rb +11 -13
  199. data/lib/active_record/relation/where_clause.rb +190 -0
  200. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  201. data/lib/active_record/result.rb +79 -42
  202. data/lib/active_record/runtime_registry.rb +6 -4
  203. data/lib/active_record/sanitization.rb +144 -121
  204. data/lib/active_record/schema.rb +21 -24
  205. data/lib/active_record/schema_dumper.rb +112 -93
  206. data/lib/active_record/schema_migration.rb +24 -17
  207. data/lib/active_record/scoping.rb +45 -26
  208. data/lib/active_record/scoping/default.rb +101 -85
  209. data/lib/active_record/scoping/named.rb +87 -33
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +5 -5
  212. data/lib/active_record/statement_cache.rb +73 -36
  213. data/lib/active_record/store.rb +127 -42
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +75 -0
  216. data/lib/active_record/tasks/database_tasks.rb +307 -100
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +55 -99
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -41
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +38 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +225 -0
  222. data/lib/active_record/timestamp.rb +86 -40
  223. data/lib/active_record/touch_later.rb +66 -0
  224. data/lib/active_record/transactions.rb +217 -151
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type.rb +78 -23
  227. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  228. data/lib/active_record/type/date.rb +4 -45
  229. data/lib/active_record/type/date_time.rb +4 -49
  230. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  231. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  232. data/lib/active_record/type/internal/timezone.rb +17 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +24 -15
  235. data/lib/active_record/type/text.rb +2 -2
  236. data/lib/active_record/type/time.rb +11 -16
  237. data/lib/active_record/type/type_map.rb +15 -17
  238. data/lib/active_record/type/unsigned_integer.rb +9 -7
  239. data/lib/active_record/type_caster.rb +9 -0
  240. data/lib/active_record/type_caster/connection.rb +34 -0
  241. data/lib/active_record/type_caster/map.rb +20 -0
  242. data/lib/active_record/validations.rb +39 -35
  243. data/lib/active_record/validations/absence.rb +25 -0
  244. data/lib/active_record/validations/associated.rb +13 -4
  245. data/lib/active_record/validations/length.rb +26 -0
  246. data/lib/active_record/validations/presence.rb +14 -13
  247. data/lib/active_record/validations/uniqueness.rb +42 -55
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/arel.rb +58 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +257 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +204 -0
  317. data/lib/arel/visitors/dot.rb +297 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +157 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +159 -0
  323. data/lib/arel/visitors/oracle12.rb +66 -0
  324. data/lib/arel/visitors/postgresql.rb +110 -0
  325. data/lib/arel/visitors/sqlite.rb +39 -0
  326. data/lib/arel/visitors/to_sql.rb +889 -0
  327. data/lib/arel/visitors/visitor.rb +46 -0
  328. data/lib/arel/visitors/where_sql.rb +23 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +7 -5
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration.rb +31 -1
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +42 -37
  335. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  336. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -2
  337. data/lib/rails/generators/active_record/model/model_generator.rb +19 -22
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  340. metadata +166 -58
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -163
  349. data/lib/active_record/attribute_set.rb +0 -81
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  352. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  353. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  354. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  355. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  356. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  359. data/lib/active_record/type/big_integer.rb +0 -13
  360. data/lib/active_record/type/binary.rb +0 -50
  361. data/lib/active_record/type/boolean.rb +0 -31
  362. data/lib/active_record/type/decimal.rb +0 -64
  363. data/lib/active_record/type/decorator.rb +0 -14
  364. data/lib/active_record/type/float.rb +0 -19
  365. data/lib/active_record/type/integer.rb +0 -59
  366. data/lib/active_record/type/mutable.rb +0 -16
  367. data/lib/active_record/type/numeric.rb +0 -36
  368. data/lib/active_record/type/string.rb +0 -40
  369. data/lib/active_record/type/time_value.rb +0 -38
  370. data/lib/active_record/type/value.rb +0 -110
  371. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  372. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,49 +1,41 @@
1
- require 'active_support/core_ext/string/conversions'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
2
4
 
3
5
  module ActiveRecord
4
6
  module Associations
5
- # Keeps track of table aliases for ActiveRecord::Associations::ClassMethods::JoinDependency and
6
- # ActiveRecord::Associations::ThroughAssociationScope
7
+ # Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
7
8
  class AliasTracker # :nodoc:
8
- attr_reader :aliases, :connection
9
-
10
- def self.empty(connection)
11
- new connection, Hash.new(0)
12
- end
13
-
14
- def self.create(connection, table_joins)
15
- if table_joins.empty?
16
- empty connection
9
+ def self.create(connection, initial_table, joins)
10
+ if joins.empty?
11
+ aliases = Hash.new(0)
17
12
  else
18
- aliases = Hash.new { |h,k|
19
- h[k] = initial_count_for(connection, k, table_joins)
13
+ aliases = Hash.new { |h, k|
14
+ h[k] = initial_count_for(connection, k, joins)
20
15
  }
21
- new connection, aliases
22
16
  end
17
+ aliases[initial_table] = 1
18
+ new(connection, aliases)
23
19
  end
24
20
 
25
21
  def self.initial_count_for(connection, name, table_joins)
26
- # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
27
- quoted_name = connection.quote_table_name(name).downcase
22
+ quoted_name = nil
28
23
 
29
24
  counts = table_joins.map do |join|
30
25
  if join.is_a?(Arel::Nodes::StringJoin)
26
+ # quoted_name should be case ignored as some database adapters (Oracle) return quoted name in uppercase
27
+ quoted_name ||= connection.quote_table_name(name)
28
+
31
29
  # Table names + table aliases
32
- join.left.downcase.scan(
33
- /join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/
30
+ join.left.scan(
31
+ /JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name}|#{name})\sON/i
34
32
  ).size
35
- elsif join.respond_to? :left
36
- join.left.table_name == name ? 1 : 0
33
+ elsif join.is_a?(Arel::Nodes::Join)
34
+ join.left.name == name ? 1 : 0
35
+ elsif join.is_a?(Hash)
36
+ join[name]
37
37
  else
38
- # this branch is reached by two tests:
39
- #
40
- # activerecord/test/cases/associations/cascaded_eager_loading_test.rb:37
41
- # with :posts
42
- #
43
- # activerecord/test/cases/associations/eager_test.rb:1133
44
- # with :comments
45
- #
46
- 0
38
+ raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
47
39
  end
48
40
  end
49
41
 
@@ -56,14 +48,14 @@ module ActiveRecord
56
48
  @connection = connection
57
49
  end
58
50
 
59
- def aliased_table_for(table_name, aliased_name)
51
+ def aliased_table_for(table_name, aliased_name, type_caster)
60
52
  if aliases[table_name].zero?
61
53
  # If it's zero, we can have our table_name
62
54
  aliases[table_name] = 1
63
- Arel::Table.new(table_name)
55
+ Arel::Table.new(table_name, type_caster: type_caster)
64
56
  else
65
57
  # Otherwise, we need to use an alias
66
- aliased_name = connection.table_alias_for(aliased_name)
58
+ aliased_name = @connection.table_alias_for(aliased_name)
67
59
 
68
60
  # Update the count
69
61
  aliases[aliased_name] += 1
@@ -73,14 +65,16 @@ module ActiveRecord
73
65
  else
74
66
  aliased_name
75
67
  end
76
- Arel::Table.new(table_name).alias(table_alias)
68
+ Arel::Table.new(table_name, type_caster: type_caster).alias(table_alias)
77
69
  end
78
70
  end
79
71
 
72
+ attr_reader :aliases
73
+
80
74
  private
81
75
 
82
76
  def truncate(name)
83
- name.slice(0, connection.table_alias_length - 2)
77
+ name.slice(0, @connection.table_alias_length - 2)
84
78
  end
85
79
  end
86
80
  end
@@ -1,4 +1,6 @@
1
- require 'active_support/core_ext/array/wrap'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/wrap"
2
4
 
3
5
  module ActiveRecord
4
6
  module Associations
@@ -8,36 +10,45 @@ module ActiveRecord
8
10
  #
9
11
  # Association
10
12
  # SingularAssociation
11
- # HasOneAssociation
13
+ # HasOneAssociation + ForeignAssociation
12
14
  # HasOneThroughAssociation + ThroughAssociation
13
15
  # BelongsToAssociation
14
16
  # BelongsToPolymorphicAssociation
15
17
  # CollectionAssociation
16
- # HasManyAssociation
18
+ # HasManyAssociation + ForeignAssociation
17
19
  # HasManyThroughAssociation + ThroughAssociation
20
+ #
21
+ # Associations in Active Record are middlemen between the object that
22
+ # holds the association, known as the <tt>owner</tt>, and the associated
23
+ # result set, known as the <tt>target</tt>. Association metadata is available in
24
+ # <tt>reflection</tt>, which is an instance of <tt>ActiveRecord::Reflection::AssociationReflection</tt>.
25
+ #
26
+ # For example, given
27
+ #
28
+ # class Blog < ActiveRecord::Base
29
+ # has_many :posts
30
+ # end
31
+ #
32
+ # blog = Blog.first
33
+ #
34
+ # The association of <tt>blog.posts</tt> has the object +blog+ as its
35
+ # <tt>owner</tt>, the collection of its posts as <tt>target</tt>, and
36
+ # the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
18
37
  class Association #:nodoc:
19
38
  attr_reader :owner, :target, :reflection
20
- attr_accessor :inversed
21
39
 
22
- delegate :options, :to => :reflection
40
+ delegate :options, to: :reflection
23
41
 
24
42
  def initialize(owner, reflection)
25
43
  reflection.check_validity!
26
44
 
27
45
  @owner, @reflection = owner, reflection
46
+ @_scope = nil
28
47
 
29
48
  reset
30
49
  reset_scope
31
50
  end
32
51
 
33
- # Returns the name of the table of the associated class:
34
- #
35
- # post.comments.aliased_table_name # => "comments"
36
- #
37
- def aliased_table_name
38
- klass.table_name
39
- end
40
-
41
52
  # Resets the \loaded flag to +false+ and sets the \target to +nil+.
42
53
  def reset
43
54
  @loaded = false
@@ -47,7 +58,9 @@ module ActiveRecord
47
58
  end
48
59
 
49
60
  # Reloads the \target and returns +self+ on success.
50
- def reload
61
+ # The QueryCache is cleared if +force+ is true.
62
+ def reload(force = false)
63
+ klass.connection.clear_query_cache if force && klass
51
64
  reset
52
65
  reset_scope
53
66
  load_target
@@ -73,7 +86,7 @@ module ActiveRecord
73
86
  #
74
87
  # Note that if the target has not been loaded, it is not considered stale.
75
88
  def stale_target?
76
- !inversed && loaded? && @stale_state != stale_state
89
+ !@inversed && loaded? && @stale_state != stale_state
77
90
  end
78
91
 
79
92
  # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -83,19 +96,7 @@ module ActiveRecord
83
96
  end
84
97
 
85
98
  def scope
86
- target_scope.merge(association_scope)
87
- end
88
-
89
- # The scope for this association.
90
- #
91
- # Note that the association_scope is merged into the target_scope only when the
92
- # scope method is called. This is because at that point the call may be surrounded
93
- # by scope.scoping { ... } or with_scope { ... } etc, which affects the scope which
94
- # actually gets built.
95
- def association_scope
96
- if klass
97
- @association_scope ||= AssociationScope.scope(self, klass.connection)
98
- end
99
+ @_scope&.spawn || target_scope.merge!(association_scope)
99
100
  end
100
101
 
101
102
  def reset_scope
@@ -104,24 +105,46 @@ module ActiveRecord
104
105
 
105
106
  # Set the inverse association, if possible
106
107
  def set_inverse_instance(record)
107
- if invertible_for?(record)
108
- inverse = record.association(inverse_reflection_for(record).name)
109
- inverse.target = owner
110
- inverse.inversed = true
108
+ if inverse = inverse_association_for(record)
109
+ inverse.inversed_from(owner)
110
+ end
111
+ record
112
+ end
113
+
114
+ def set_inverse_instance_from_queries(record)
115
+ if inverse = inverse_association_for(record)
116
+ inverse.inversed_from_queries(owner)
111
117
  end
112
118
  record
113
119
  end
114
120
 
121
+ # Remove the inverse association, if possible
122
+ def remove_inverse_instance(record)
123
+ if inverse = inverse_association_for(record)
124
+ inverse.inversed_from(nil)
125
+ end
126
+ end
127
+
128
+ def inversed_from(record)
129
+ self.target = record
130
+ @inversed = !!record
131
+ end
132
+ alias :inversed_from_queries :inversed_from
133
+
115
134
  # Returns the class of the target. belongs_to polymorphic overrides this to look at the
116
135
  # polymorphic_type field on the owner.
117
136
  def klass
118
137
  reflection.klass
119
138
  end
120
139
 
121
- # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
122
- # through association's scope)
123
- def target_scope
124
- AssociationRelation.create(klass, klass.arel_table, self).merge!(klass.all)
140
+ def extensions
141
+ extensions = klass.default_extensions | reflection.extensions
142
+
143
+ if reflection.scope
144
+ extensions |= reflection.scope_for(klass.unscoped, owner).extensions
145
+ end
146
+
147
+ extensions
125
148
  end
126
149
 
127
150
  # Loads the \target if needed and returns it.
@@ -143,17 +166,9 @@ module ActiveRecord
143
166
  reset
144
167
  end
145
168
 
146
- def interpolate(sql, record = nil)
147
- if sql.respond_to?(:to_proc)
148
- owner.instance_exec(record, &sql)
149
- else
150
- sql
151
- end
152
- end
153
-
154
- # We can't dump @reflection since it contains the scope proc
169
+ # We can't dump @reflection and @through_reflection since it contains the scope proc
155
170
  def marshal_dump
156
- ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
171
+ ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
157
172
  [@reflection.name, ivars]
158
173
  end
159
174
 
@@ -163,14 +178,67 @@ module ActiveRecord
163
178
  @reflection = @owner.class._reflect_on_association(reflection_name)
164
179
  end
165
180
 
166
- def initialize_attributes(record) #:nodoc:
181
+ def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
182
+ except_from_scope_attributes ||= {}
167
183
  skip_assign = [reflection.foreign_key, reflection.type].compact
168
- attributes = create_scope.except(*(record.changed - skip_assign))
169
- record.assign_attributes(attributes)
184
+ assigned_keys = record.changed_attribute_names_to_save
185
+ assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
186
+ attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
187
+ record.send(:_assign_attributes, attributes) if attributes.any?
170
188
  set_inverse_instance(record)
171
189
  end
172
190
 
191
+ def create(attributes = {}, &block)
192
+ _create_record(attributes, &block)
193
+ end
194
+
195
+ def create!(attributes = {}, &block)
196
+ _create_record(attributes, true, &block)
197
+ end
198
+
199
+ def scoping(relation, &block)
200
+ @_scope = relation
201
+ relation.scoping(&block)
202
+ ensure
203
+ @_scope = nil
204
+ end
205
+
173
206
  private
207
+ def find_target
208
+ scope = self.scope
209
+ return scope.to_a if skip_statement_cache?(scope)
210
+
211
+ conn = klass.connection
212
+ sc = reflection.association_scope_cache(conn, owner) do |params|
213
+ as = AssociationScope.create { params.bind }
214
+ target_scope.merge!(as.scope(self))
215
+ end
216
+
217
+ binds = AssociationScope.get_bind_values(owner, reflection.chain)
218
+ sc.execute(binds, conn) { |record| set_inverse_instance(record) } || []
219
+ end
220
+
221
+ # The scope for this association.
222
+ #
223
+ # Note that the association_scope is merged into the target_scope only when the
224
+ # scope method is called. This is because at that point the call may be surrounded
225
+ # by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
226
+ # actually gets built.
227
+ def association_scope
228
+ if klass
229
+ @association_scope ||= AssociationScope.scope(self)
230
+ end
231
+ end
232
+
233
+ # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
234
+ # through association's scope)
235
+ def target_scope
236
+ AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
237
+ end
238
+
239
+ def scope_for_create
240
+ scope.scope_for_create
241
+ end
174
242
 
175
243
  def find_target?
176
244
  !loaded? && (!owner.new_record? || foreign_key_present?) && klass
@@ -182,8 +250,8 @@ module ActiveRecord
182
250
  if (reflection.has_one? || reflection.collection?) && !options[:through]
183
251
  attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
184
252
 
185
- if reflection.options[:as]
186
- attributes[reflection.type] = owner.class.base_class.name
253
+ if reflection.type
254
+ attributes[reflection.type] = owner.class.polymorphic_name
187
255
  end
188
256
  end
189
257
 
@@ -214,12 +282,19 @@ module ActiveRecord
214
282
  unless record.is_a?(reflection.klass)
215
283
  fresh_class = reflection.class_name.safe_constantize
216
284
  unless fresh_class && record.is_a?(fresh_class)
217
- message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
285
+ message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, "\
286
+ "got #{record.inspect} which is an instance of #{record.class}(##{record.class.object_id})"
218
287
  raise ActiveRecord::AssociationTypeMismatch, message
219
288
  end
220
289
  end
221
290
  end
222
291
 
292
+ def inverse_association_for(record)
293
+ if invertible_for?(record)
294
+ record.association(inverse_reflection_for(record).name)
295
+ end
296
+ end
297
+
223
298
  # Can be redefined by subclasses, notably polymorphic belongs_to
224
299
  # The record parameter is necessary to support polymorphic inverses as we must check for
225
300
  # the association in the specific class of the record.
@@ -242,22 +317,22 @@ module ActiveRecord
242
317
  # so that when stale_state is different from the value stored on the last find_target,
243
318
  # the target is stale.
244
319
  #
245
- # This is only relevant to certain associations, which is why it returns nil by default.
320
+ # This is only relevant to certain associations, which is why it returns +nil+ by default.
246
321
  def stale_state
247
322
  end
248
323
 
249
324
  def build_record(attributes)
250
325
  reflection.build_association(attributes) do |record|
251
- initialize_attributes(record)
326
+ initialize_attributes(record, attributes)
327
+ yield(record) if block_given?
252
328
  end
253
329
  end
254
330
 
255
331
  # Returns true if statement cache should be skipped on the association reader.
256
- def skip_statement_cache?
257
- reflection.scope_chain.any?(&:any?) ||
332
+ def skip_statement_cache?(scope)
333
+ reflection.has_scope? ||
258
334
  scope.eager_loading? ||
259
- klass.current_scope ||
260
- klass.default_scopes.any? ||
335
+ klass.scope_attributes? ||
261
336
  reflection.source_reflection.active_record.default_scopes.any?
262
337
  end
263
338
  end
@@ -1,46 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class AssociationScope #:nodoc:
4
- def self.scope(association, connection)
5
- INSTANCE.scope association, connection
6
- end
7
-
8
- class BindSubstitution
9
- def initialize(block)
10
- @block = block
11
- end
12
-
13
- def bind_value(scope, column, value, alias_tracker)
14
- substitute = alias_tracker.connection.substitute_at(column)
15
- scope.bind_values += [[column, @block.call(value)]]
16
- substitute
17
- end
6
+ def self.scope(association)
7
+ INSTANCE.scope(association)
18
8
  end
19
9
 
20
10
  def self.create(&block)
21
- block = block ? block : lambda { |val| val }
22
- new BindSubstitution.new(block)
11
+ block ||= lambda { |val| val }
12
+ new(block)
23
13
  end
24
14
 
25
- def initialize(bind_substitution)
26
- @bind_substitution = bind_substitution
15
+ def initialize(value_transformation)
16
+ @value_transformation = value_transformation
27
17
  end
28
18
 
29
19
  INSTANCE = create
30
20
 
31
- def scope(association, connection)
32
- klass = association.klass
33
- reflection = association.reflection
34
- scope = klass.unscoped
35
- owner = association.owner
36
- alias_tracker = AliasTracker.empty connection
21
+ def scope(association)
22
+ klass = association.klass
23
+ reflection = association.reflection
24
+ scope = klass.unscoped
25
+ owner = association.owner
26
+ chain = get_chain(reflection, association, scope.alias_tracker)
37
27
 
38
- scope.extending! Array(reflection.options[:extend])
39
- add_constraints(scope, owner, klass, reflection, alias_tracker)
40
- end
41
-
42
- def join_type
43
- Arel::Nodes::InnerJoin
28
+ scope.extending! reflection.extensions
29
+ scope = add_constraints(scope, owner, chain)
30
+ scope.limit!(1) unless reflection.collection?
31
+ scope
44
32
  end
45
33
 
46
34
  def self.get_bind_values(owner, chain)
@@ -49,147 +37,130 @@ module ActiveRecord
49
37
 
50
38
  binds << last_reflection.join_id_for(owner)
51
39
  if last_reflection.type
52
- binds << owner.class.base_class.name
40
+ binds << owner.class.polymorphic_name
53
41
  end
54
42
 
55
43
  chain.each_cons(2).each do |reflection, next_reflection|
56
44
  if reflection.type
57
- binds << next_reflection.klass.base_class.name
45
+ binds << next_reflection.klass.polymorphic_name
58
46
  end
59
47
  end
60
48
  binds
61
49
  end
62
50
 
63
51
  private
52
+ attr_reader :value_transformation
64
53
 
65
- def construct_tables(chain, klass, refl, alias_tracker)
66
- chain.map do |reflection|
67
- alias_tracker.aliased_table_for(
68
- table_name_for(reflection, klass, refl),
69
- table_alias_for(reflection, refl, reflection != refl)
70
- )
54
+ def join(table, constraint)
55
+ table.create_join(table, table.create_on(constraint))
71
56
  end
72
- end
73
57
 
74
- def table_alias_for(reflection, refl, join = false)
75
- name = "#{reflection.plural_name}_#{alias_suffix(refl)}"
76
- name << "_join" if join
77
- name
78
- end
58
+ def last_chain_scope(scope, reflection, owner)
59
+ join_keys = reflection.join_keys
60
+ key = join_keys.key
61
+ foreign_key = join_keys.foreign_key
79
62
 
80
- def join(table, constraint)
81
- table.create_join(table, table.create_on(constraint), join_type)
82
- end
63
+ table = reflection.aliased_table
64
+ value = transform_value(owner[foreign_key])
65
+ scope = apply_scope(scope, table, key, value)
83
66
 
84
- def column_for(table_name, column_name, alias_tracker)
85
- columns = alias_tracker.connection.schema_cache.columns_hash(table_name)
86
- columns[column_name]
87
- end
88
-
89
- def bind_value(scope, column, value, alias_tracker)
90
- @bind_substitution.bind_value scope, column, value, alias_tracker
91
- end
92
-
93
- def bind(scope, table_name, column_name, value, tracker)
94
- column = column_for table_name, column_name, tracker
95
- bind_value scope, column, value, tracker
96
- end
97
-
98
- def last_chain_scope(scope, table, reflection, owner, tracker, assoc_klass)
99
- join_keys = reflection.join_keys(assoc_klass)
100
- key = join_keys.key
101
- foreign_key = join_keys.foreign_key
102
-
103
- bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key], tracker
104
- scope = scope.where(table[key].eq(bind_val))
67
+ if reflection.type
68
+ polymorphic_type = transform_value(owner.class.polymorphic_name)
69
+ scope = apply_scope(scope, table, reflection.type, polymorphic_type)
70
+ end
105
71
 
106
- if reflection.type
107
- value = owner.class.base_class.name
108
- bind_val = bind scope, table.table_name, reflection.type, value, tracker
109
- scope = scope.where(table[reflection.type].eq(bind_val))
110
- else
111
72
  scope
112
73
  end
113
- end
114
74
 
115
- def next_chain_scope(scope, table, reflection, tracker, assoc_klass, foreign_table, next_reflection)
116
- join_keys = reflection.join_keys(assoc_klass)
117
- key = join_keys.key
118
- foreign_key = join_keys.foreign_key
75
+ def transform_value(value)
76
+ value_transformation.call(value)
77
+ end
119
78
 
120
- constraint = table[key].eq(foreign_table[foreign_key])
79
+ def next_chain_scope(scope, reflection, next_reflection)
80
+ join_keys = reflection.join_keys
81
+ key = join_keys.key
82
+ foreign_key = join_keys.foreign_key
121
83
 
122
- if reflection.type
123
- value = next_reflection.klass.base_class.name
124
- bind_val = bind scope, table.table_name, reflection.type, value, tracker
125
- scope = scope.where(table[reflection.type].eq(bind_val))
84
+ table = reflection.aliased_table
85
+ foreign_table = next_reflection.aliased_table
86
+ constraint = table[key].eq(foreign_table[foreign_key])
87
+
88
+ if reflection.type
89
+ value = transform_value(next_reflection.klass.polymorphic_name)
90
+ scope = apply_scope(scope, table, reflection.type, value)
91
+ end
92
+
93
+ scope.joins!(join(foreign_table, constraint))
126
94
  end
127
95
 
128
- scope = scope.joins(join(foreign_table, constraint))
129
- end
96
+ class ReflectionProxy < SimpleDelegator # :nodoc:
97
+ attr_reader :aliased_table
130
98
 
131
- def add_constraints(scope, owner, assoc_klass, refl, tracker)
132
- chain = refl.chain
133
- scope_chain = refl.scope_chain
99
+ def initialize(reflection, aliased_table)
100
+ super(reflection)
101
+ @aliased_table = aliased_table
102
+ end
134
103
 
135
- tables = construct_tables(chain, assoc_klass, refl, tracker)
104
+ def all_includes; nil; end
105
+ end
136
106
 
137
- owner_reflection = chain.last
138
- table = tables.last
139
- scope = last_chain_scope(scope, table, owner_reflection, owner, tracker, assoc_klass)
107
+ def get_chain(reflection, association, tracker)
108
+ name = reflection.name
109
+ chain = [Reflection::RuntimeReflection.new(reflection, association)]
110
+ reflection.chain.drop(1).each do |refl|
111
+ aliased_table = tracker.aliased_table_for(
112
+ refl.table_name,
113
+ refl.alias_candidate(name),
114
+ refl.klass.type_caster
115
+ )
116
+ chain << ReflectionProxy.new(refl, aliased_table)
117
+ end
118
+ chain
119
+ end
140
120
 
141
- chain.each_with_index do |reflection, i|
142
- table, foreign_table = tables.shift, tables.first
121
+ def add_constraints(scope, owner, chain)
122
+ scope = last_chain_scope(scope, chain.last, owner)
143
123
 
144
- unless reflection == chain.last
145
- next_reflection = chain[i + 1]
146
- scope = next_chain_scope(scope, table, reflection, tracker, assoc_klass, foreign_table, next_reflection)
124
+ chain.each_cons(2) do |reflection, next_reflection|
125
+ scope = next_chain_scope(scope, reflection, next_reflection)
147
126
  end
148
127
 
149
- is_first_chain = i == 0
150
- klass = is_first_chain ? assoc_klass : reflection.klass
128
+ chain_head = chain.first
129
+ chain.reverse_each do |reflection|
130
+ # Exclude the scope of the association itself, because that
131
+ # was already merged in the #scope method.
132
+ reflection.constraints.each do |scope_chain_item|
133
+ item = eval_scope(reflection, scope_chain_item, owner)
151
134
 
152
- # Exclude the scope of the association itself, because that
153
- # was already merged in the #scope method.
154
- scope_chain[i].each do |scope_chain_item|
155
- item = eval_scope(klass, scope_chain_item, owner)
135
+ if scope_chain_item == chain_head.scope
136
+ scope.merge! item.except(:where, :includes, :unscope, :order)
137
+ end
156
138
 
157
- if scope_chain_item == refl.scope
158
- scope.merge! item.except(:where, :includes, :bind)
159
- end
139
+ reflection.all_includes do
140
+ scope.includes! item.includes_values
141
+ end
160
142
 
161
- if is_first_chain
162
- scope.includes! item.includes_values
143
+ scope.unscope!(*item.unscope_values)
144
+ scope.where_clause += item.where_clause
145
+ scope.order_values = item.order_values | scope.order_values
163
146
  end
164
-
165
- scope.unscope!(*item.unscope_values)
166
- scope.where_values += item.where_values
167
- scope.bind_values += item.bind_values
168
- scope.order_values |= item.order_values
169
147
  end
170
- end
171
-
172
- scope
173
- end
174
148
 
175
- def alias_suffix(refl)
176
- refl.name
177
- end
149
+ scope
150
+ end
178
151
 
179
- def table_name_for(reflection, klass, refl)
180
- if reflection == refl
181
- # If this is a polymorphic belongs_to, we want to get the klass from the
182
- # association because it depends on the polymorphic_type attribute of
183
- # the owner
184
- klass.table_name
185
- else
186
- reflection.table_name
152
+ def apply_scope(scope, table, key, value)
153
+ if scope.table == table
154
+ scope.where!(key => value)
155
+ else
156
+ scope.where!(table.name => { key => value })
157
+ end
187
158
  end
188
- end
189
159
 
190
- def eval_scope(klass, scope, owner)
191
- klass.unscoped.instance_exec(owner, &scope)
192
- end
160
+ def eval_scope(reflection, scope, owner)
161
+ relation = reflection.build_scope(reflection.aliased_table)
162
+ relation.instance_exec(owner, &scope) || relation
163
+ end
193
164
  end
194
165
  end
195
166
  end