activerecord 4.2.11.3 → 6.0.0

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

Potentially problematic release.


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

Files changed (372) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +613 -1643
  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 +11 -6
  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 +125 -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 +131 -287
  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 +137 -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 +91 -37
  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 +796 -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 +234 -115
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -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 +460 -204
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +510 -635
  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 +200 -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 +64 -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 +551 -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 +118 -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 +290 -345
  127. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  128. data/lib/active_record/connection_handling.rb +176 -41
  129. data/lib/active_record/core.rb +251 -231
  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 +92 -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 +312 -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 +328 -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 +518 -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 +277 -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 +575 -394
  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 +86 -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 +224 -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 +216 -150
  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 +51 -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 +164 -59
  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,18 +10,34 @@ 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!
@@ -30,14 +48,6 @@ module ActiveRecord
30
48
  reset_scope
31
49
  end
32
50
 
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
51
  # Resets the \loaded flag to +false+ and sets the \target to +nil+.
42
52
  def reset
43
53
  @loaded = false
@@ -47,7 +57,9 @@ module ActiveRecord
47
57
  end
48
58
 
49
59
  # Reloads the \target and returns +self+ on success.
50
- def reload
60
+ # The QueryCache is cleared if +force+ is true.
61
+ def reload(force = false)
62
+ klass.connection.clear_query_cache if force && klass
51
63
  reset
52
64
  reset_scope
53
65
  load_target
@@ -73,7 +85,7 @@ module ActiveRecord
73
85
  #
74
86
  # Note that if the target has not been loaded, it is not considered stale.
75
87
  def stale_target?
76
- !inversed && loaded? && @stale_state != stale_state
88
+ !@inversed && loaded? && @stale_state != stale_state
77
89
  end
78
90
 
79
91
  # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -83,19 +95,7 @@ module ActiveRecord
83
95
  end
84
96
 
85
97
  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
98
+ target_scope.merge!(association_scope)
99
99
  end
100
100
 
101
101
  def reset_scope
@@ -104,24 +104,46 @@ module ActiveRecord
104
104
 
105
105
  # Set the inverse association, if possible
106
106
  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
107
+ if inverse = inverse_association_for(record)
108
+ inverse.inversed_from(owner)
109
+ end
110
+ record
111
+ end
112
+
113
+ def set_inverse_instance_from_queries(record)
114
+ if inverse = inverse_association_for(record)
115
+ inverse.inversed_from_queries(owner)
111
116
  end
112
117
  record
113
118
  end
114
119
 
120
+ # Remove the inverse association, if possible
121
+ def remove_inverse_instance(record)
122
+ if inverse = inverse_association_for(record)
123
+ inverse.inversed_from(nil)
124
+ end
125
+ end
126
+
127
+ def inversed_from(record)
128
+ self.target = record
129
+ @inversed = !!record
130
+ end
131
+ alias :inversed_from_queries :inversed_from
132
+
115
133
  # Returns the class of the target. belongs_to polymorphic overrides this to look at the
116
134
  # polymorphic_type field on the owner.
117
135
  def klass
118
136
  reflection.klass
119
137
  end
120
138
 
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)
139
+ def extensions
140
+ extensions = klass.default_extensions | reflection.extensions
141
+
142
+ if reflection.scope
143
+ extensions |= reflection.scope_for(klass.unscoped, owner).extensions
144
+ end
145
+
146
+ extensions
125
147
  end
126
148
 
127
149
  # Loads the \target if needed and returns it.
@@ -143,17 +165,9 @@ module ActiveRecord
143
165
  reset
144
166
  end
145
167
 
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
168
+ # We can't dump @reflection and @through_reflection since it contains the scope proc
155
169
  def marshal_dump
156
- ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
170
+ ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
157
171
  [@reflection.name, ivars]
158
172
  end
159
173
 
@@ -163,14 +177,60 @@ module ActiveRecord
163
177
  @reflection = @owner.class._reflect_on_association(reflection_name)
164
178
  end
165
179
 
166
- def initialize_attributes(record) #:nodoc:
180
+ def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
181
+ except_from_scope_attributes ||= {}
167
182
  skip_assign = [reflection.foreign_key, reflection.type].compact
168
- attributes = create_scope.except(*(record.changed - skip_assign))
169
- record.assign_attributes(attributes)
183
+ assigned_keys = record.changed_attribute_names_to_save
184
+ assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
185
+ attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
186
+ record.send(:_assign_attributes, attributes) if attributes.any?
170
187
  set_inverse_instance(record)
171
188
  end
172
189
 
190
+ def create(attributes = {}, &block)
191
+ _create_record(attributes, &block)
192
+ end
193
+
194
+ def create!(attributes = {}, &block)
195
+ _create_record(attributes, true, &block)
196
+ end
197
+
173
198
  private
199
+ def find_target
200
+ scope = self.scope
201
+ return scope.to_a if skip_statement_cache?(scope)
202
+
203
+ conn = klass.connection
204
+ sc = reflection.association_scope_cache(conn, owner) do |params|
205
+ as = AssociationScope.create { params.bind }
206
+ target_scope.merge!(as.scope(self))
207
+ end
208
+
209
+ binds = AssociationScope.get_bind_values(owner, reflection.chain)
210
+ sc.execute(binds, conn) { |record| set_inverse_instance(record) } || []
211
+ end
212
+
213
+ # The scope for this association.
214
+ #
215
+ # Note that the association_scope is merged into the target_scope only when the
216
+ # scope method is called. This is because at that point the call may be surrounded
217
+ # by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
218
+ # actually gets built.
219
+ def association_scope
220
+ if klass
221
+ @association_scope ||= AssociationScope.scope(self)
222
+ end
223
+ end
224
+
225
+ # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
226
+ # through association's scope)
227
+ def target_scope
228
+ AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
229
+ end
230
+
231
+ def scope_for_create
232
+ scope.scope_for_create
233
+ end
174
234
 
175
235
  def find_target?
176
236
  !loaded? && (!owner.new_record? || foreign_key_present?) && klass
@@ -182,8 +242,8 @@ module ActiveRecord
182
242
  if (reflection.has_one? || reflection.collection?) && !options[:through]
183
243
  attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
184
244
 
185
- if reflection.options[:as]
186
- attributes[reflection.type] = owner.class.base_class.name
245
+ if reflection.type
246
+ attributes[reflection.type] = owner.class.polymorphic_name
187
247
  end
188
248
  end
189
249
 
@@ -214,12 +274,19 @@ module ActiveRecord
214
274
  unless record.is_a?(reflection.klass)
215
275
  fresh_class = reflection.class_name.safe_constantize
216
276
  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})"
277
+ message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, "\
278
+ "got #{record.inspect} which is an instance of #{record.class}(##{record.class.object_id})"
218
279
  raise ActiveRecord::AssociationTypeMismatch, message
219
280
  end
220
281
  end
221
282
  end
222
283
 
284
+ def inverse_association_for(record)
285
+ if invertible_for?(record)
286
+ record.association(inverse_reflection_for(record).name)
287
+ end
288
+ end
289
+
223
290
  # Can be redefined by subclasses, notably polymorphic belongs_to
224
291
  # The record parameter is necessary to support polymorphic inverses as we must check for
225
292
  # the association in the specific class of the record.
@@ -242,22 +309,22 @@ module ActiveRecord
242
309
  # so that when stale_state is different from the value stored on the last find_target,
243
310
  # the target is stale.
244
311
  #
245
- # This is only relevant to certain associations, which is why it returns nil by default.
312
+ # This is only relevant to certain associations, which is why it returns +nil+ by default.
246
313
  def stale_state
247
314
  end
248
315
 
249
316
  def build_record(attributes)
250
317
  reflection.build_association(attributes) do |record|
251
- initialize_attributes(record)
318
+ initialize_attributes(record, attributes)
319
+ yield(record) if block_given?
252
320
  end
253
321
  end
254
322
 
255
323
  # Returns true if statement cache should be skipped on the association reader.
256
- def skip_statement_cache?
257
- reflection.scope_chain.any?(&:any?) ||
324
+ def skip_statement_cache?(scope)
325
+ reflection.has_scope? ||
258
326
  scope.eager_loading? ||
259
- klass.current_scope ||
260
- klass.default_scopes.any? ||
327
+ klass.scope_attributes? ||
261
328
  reflection.source_reflection.active_record.default_scopes.any?
262
329
  end
263
330
  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