activerecord 4.2.0 → 6.1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1221 -796
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +267 -249
  8. data/lib/active_record/association_relation.rb +45 -7
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +172 -67
  11. data/lib/active_record/associations/association_scope.rb +105 -129
  12. data/lib/active_record/associations/belongs_to_association.rb +85 -59
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -33
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +168 -279
  22. data/lib/active_record/associations/collection_proxy.rb +263 -155
  23. data/lib/active_record/associations/foreign_association.rb +33 -0
  24. data/lib/active_record/associations/has_many_association.rb +57 -84
  25. data/lib/active_record/associations/has_many_through_association.rb +70 -82
  26. data/lib/active_record/associations/has_one_association.rb +74 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -73
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +175 -164
  32. data/lib/active_record/associations/preloader/association.rb +107 -112
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +99 -96
  35. data/lib/active_record/associations/singular_association.rb +18 -45
  36. data/lib/active_record/associations/through_association.rb +49 -24
  37. data/lib/active_record/associations.rb +1845 -1597
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -138
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -36
  46. data/lib/active_record/attribute_methods/write.rb +25 -56
  47. data/lib/active_record/attribute_methods.rb +153 -162
  48. data/lib/active_record/attributes.rb +234 -70
  49. data/lib/active_record/autosave_association.rb +157 -69
  50. data/lib/active_record/base.rb +49 -50
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +46 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +271 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +78 -161
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -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 +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +499 -293
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +595 -382
  119. data/lib/active_record/connection_adapters/schema_cache.rb +191 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -389
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +488 -243
  133. data/lib/active_record/counter_cache.rb +71 -50
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +273 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +212 -94
  143. data/lib/active_record/errors.rb +225 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +11 -6
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +273 -496
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +64 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +52 -0
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +103 -95
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +298 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +685 -309
  170. data/lib/active_record/model_schema.rb +420 -113
  171. data/lib/active_record/nested_attributes.rb +265 -216
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +574 -135
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +175 -54
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +533 -216
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +485 -310
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +326 -244
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +318 -256
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +99 -84
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +139 -96
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -409
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +23 -21
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -342
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -26
  209. data/lib/active_record/scoping/default.rb +96 -82
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +133 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +366 -129
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +291 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +181 -152
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -41
  231. data/lib/active_record/type/date_time.rb +4 -38
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +33 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +65 -48
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +44 -28
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -10
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +175 -65
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  347. data/lib/active_record/attribute.rb +0 -149
  348. data/lib/active_record/attribute_decorators.rb +0 -66
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  351. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -30
  363. data/lib/active_record/type/decimal.rb +0 -40
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -55
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -36
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -101
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  374. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  # = Active Record Association Collection
@@ -10,9 +12,9 @@ module ActiveRecord
10
12
  # HasManyAssociation => has_many
11
13
  # HasManyThroughAssociation + ThroughAssociation => has_many :through
12
14
  #
13
- # CollectionAssociation class provides common methods to the collections
15
+ # The CollectionAssociation class provides common methods to the collections
14
16
  # defined by +has_and_belongs_to_many+, +has_many+ or +has_many+ with
15
- # +:through association+ option.
17
+ # the +:through association+ option.
16
18
  #
17
19
  # You need to be careful with assumptions regarding the target: The proxy
18
20
  # does not fetch records from the database until it needs them, but new
@@ -24,22 +26,14 @@ module ActiveRecord
24
26
  # If you need to work on all current children, new and existing records,
25
27
  # +load_target+ and the +loaded+ flag are your friends.
26
28
  class CollectionAssociation < Association #:nodoc:
27
-
28
29
  # Implements the reader method, e.g. foo.items for Foo.has_many :items
29
- def reader(force_reload = false)
30
- if force_reload
31
- klass.uncached { reload }
32
- elsif stale_target?
30
+ def reader
31
+ if stale_target?
33
32
  reload
34
33
  end
35
34
 
36
- if owner.new_record?
37
- # Cache the proxy separately before the owner has an id
38
- # or else a post-save proxy will still lack the id
39
- @new_record_proxy ||= CollectionProxy.create(klass, self)
40
- else
41
- @proxy ||= CollectionProxy.create(klass, self)
42
- end
35
+ @proxy ||= CollectionProxy.create(klass, self)
36
+ @proxy.reset_scope
43
37
  end
44
38
 
45
39
  # Implements the writer method, e.g. foo.items= for Foo.has_many :items
@@ -50,107 +44,76 @@ module ActiveRecord
50
44
  # Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
51
45
  def ids_reader
52
46
  if loaded?
53
- load_target.map do |record|
54
- record.send(reflection.association_primary_key)
55
- end
47
+ target.pluck(reflection.association_primary_key)
48
+ elsif !target.empty?
49
+ load_target.pluck(reflection.association_primary_key)
56
50
  else
57
- column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
58
- scope.pluck(column)
51
+ @association_ids ||= scope.pluck(reflection.association_primary_key)
59
52
  end
60
53
  end
61
54
 
62
55
  # Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
63
56
  def ids_writer(ids)
64
- pk_type = reflection.primary_key_type
65
- ids = Array(ids).reject { |id| id.blank? }
66
- ids.map! { |i| pk_type.type_cast_from_user(i) }
67
- replace(klass.find(ids).index_by { |r| r.id }.values_at(*ids))
57
+ primary_key = reflection.association_primary_key
58
+ pk_type = klass.type_for_attribute(primary_key)
59
+ ids = Array(ids).compact_blank
60
+ ids.map! { |i| pk_type.cast(i) }
61
+
62
+ records = klass.where(primary_key => ids).index_by do |r|
63
+ r.public_send(primary_key)
64
+ end.values_at(*ids).compact
65
+
66
+ if records.size != ids.size
67
+ found_ids = records.map { |record| record.public_send(primary_key) }
68
+ not_found_ids = ids - found_ids
69
+ klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids)
70
+ else
71
+ replace(records)
72
+ end
68
73
  end
69
74
 
70
75
  def reset
71
76
  super
72
77
  @target = []
73
- end
74
-
75
- def select(*fields)
76
- if block_given?
77
- load_target.select.each { |e| yield e }
78
- else
79
- scope.select(*fields)
80
- end
78
+ @replaced_or_added_targets = Set.new
79
+ @association_ids = nil
81
80
  end
82
81
 
83
82
  def find(*args)
84
- if block_given?
85
- load_target.find(*args) { |*block_args| yield(*block_args) }
86
- else
87
- if options[:inverse_of] && loaded?
88
- args_flatten = args.flatten
89
- raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args_flatten.blank?
90
- result = find_by_scan(*args)
91
-
92
- result_size = Array(result).size
93
- if !result || result_size != args_flatten.size
94
- scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
95
- else
96
- result
97
- end
98
- else
99
- scope.find(*args)
100
- end
101
- end
102
- end
103
-
104
- def first(*args)
105
- first_nth_or_last(:first, *args)
106
- end
107
-
108
- def second(*args)
109
- first_nth_or_last(:second, *args)
110
- end
111
-
112
- def third(*args)
113
- first_nth_or_last(:third, *args)
114
- end
83
+ if options[:inverse_of] && loaded?
84
+ args_flatten = args.flatten
85
+ model = scope.klass
115
86
 
116
- def fourth(*args)
117
- first_nth_or_last(:fourth, *args)
118
- end
87
+ if args_flatten.blank?
88
+ error_message = "Couldn't find #{model.name} without an ID"
89
+ raise RecordNotFound.new(error_message, model.name, model.primary_key, args)
90
+ end
119
91
 
120
- def fifth(*args)
121
- first_nth_or_last(:fifth, *args)
122
- end
92
+ result = find_by_scan(*args)
123
93
 
124
- def forty_two(*args)
125
- first_nth_or_last(:forty_two, *args)
126
- end
127
-
128
- def last(*args)
129
- first_nth_or_last(:last, *args)
94
+ result_size = Array(result).size
95
+ if !result || result_size != args_flatten.size
96
+ scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
97
+ else
98
+ result
99
+ end
100
+ else
101
+ scope.find(*args)
102
+ end
130
103
  end
131
104
 
132
- def build(attributes = {}, &block)
105
+ def build(attributes = nil, &block)
133
106
  if attributes.is_a?(Array)
134
107
  attributes.collect { |attr| build(attr, &block) }
135
108
  else
136
- add_to_target(build_record(attributes)) do |record|
137
- yield(record) if block_given?
138
- end
109
+ add_to_target(build_record(attributes, &block), replace: true)
139
110
  end
140
111
  end
141
112
 
142
- def create(attributes = {}, &block)
143
- _create_record(attributes, &block)
144
- end
145
-
146
- def create!(attributes = {}, &block)
147
- _create_record(attributes, true, &block)
148
- end
149
-
150
- # Add +records+ to this association. Returns +self+ so method calls may
151
- # be chained. Since << flattens its argument list and inserts each record,
152
- # +push+ and +concat+ behave identically.
113
+ # Add +records+ to this association. Since +<<+ flattens its argument list
114
+ # and inserts each record, +push+ and +concat+ behave identically.
153
115
  def concat(*records)
116
+ records = records.flatten
154
117
  if owner.new_record?
155
118
  load_target
156
119
  concat_records(records)
@@ -193,12 +156,12 @@ module ActiveRecord
193
156
  end
194
157
 
195
158
  dependent = if dependent
196
- dependent
197
- elsif options[:dependent] == :destroy
198
- :delete_all
199
- else
200
- options[:dependent]
201
- end
159
+ dependent
160
+ elsif options[:dependent] == :destroy
161
+ :delete_all
162
+ else
163
+ options[:dependent]
164
+ end
202
165
 
203
166
  delete_or_nullify_all_records(dependent).tap do
204
167
  reset
@@ -216,32 +179,6 @@ module ActiveRecord
216
179
  end
217
180
  end
218
181
 
219
- # Count all records using SQL. Construct options and pass them with
220
- # scope to the target class's +count+.
221
- def count(column_name = nil, count_options = {})
222
- # TODO: Remove count_options argument as soon we remove support to
223
- # activerecord-deprecated_finders.
224
- column_name, count_options = nil, column_name if column_name.is_a?(Hash)
225
-
226
- relation = scope
227
- if association_scope.distinct_value
228
- # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
229
- column_name ||= reflection.klass.primary_key
230
- relation = relation.distinct
231
- end
232
-
233
- value = relation.count(column_name)
234
-
235
- limit = options[:limit]
236
- offset = options[:offset]
237
-
238
- if limit || offset
239
- [ [value - offset.to_i, 0].max, limit.to_i ].min
240
- else
241
- value
242
- end
243
- end
244
-
245
182
  # Removes +records+ from this association calling +before_remove+ and
246
183
  # +after_remove+ callbacks.
247
184
  #
@@ -250,12 +187,7 @@ module ActiveRecord
250
187
  # are actually removed from the database, that depends precisely on
251
188
  # +delete_records+. They are in any case removed from the collection.
252
189
  def delete(*records)
253
- return if records.empty?
254
- _options = records.extract_options!
255
- dependent = _options[:dependent] || options[:dependent]
256
-
257
- records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
258
- delete_or_destroy(records, dependent)
190
+ delete_or_destroy(records, options[:dependent])
259
191
  end
260
192
 
261
193
  # Deletes the +records+ and removes them from this association calling
@@ -264,8 +196,6 @@ module ActiveRecord
264
196
  # Note that this method removes records from the database ignoring the
265
197
  # +:dependent+ option.
266
198
  def destroy(*records)
267
- return if records.empty?
268
- records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
269
199
  delete_or_destroy(records, :destroy)
270
200
  end
271
201
 
@@ -281,74 +211,35 @@ module ActiveRecord
281
211
  # +count_records+, which is a method descendants have to provide.
282
212
  def size
283
213
  if !find_target? || loaded?
284
- if association_scope.distinct_value
285
- target.uniq.size
286
- else
287
- target.size
288
- end
289
- elsif !loaded? && !association_scope.group_values.empty?
214
+ target.size
215
+ elsif @association_ids
216
+ @association_ids.size
217
+ elsif !association_scope.group_values.empty?
290
218
  load_target.size
291
- elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array)
292
- unsaved_records = target.select { |r| r.new_record? }
219
+ elsif !association_scope.distinct_value && !target.empty?
220
+ unsaved_records = target.select(&:new_record?)
293
221
  unsaved_records.size + count_records
294
222
  else
295
223
  count_records
296
224
  end
297
225
  end
298
226
 
299
- # Returns the size of the collection calling +size+ on the target.
300
- #
301
- # If the collection has been already loaded +length+ and +size+ are
302
- # equivalent. If not and you are going to need the records anyway this
303
- # method will take one less query. Otherwise +size+ is more efficient.
304
- def length
305
- load_target.size
306
- end
307
-
308
227
  # Returns true if the collection is empty.
309
228
  #
310
229
  # If the collection has been loaded
311
230
  # it is equivalent to <tt>collection.size.zero?</tt>. If the
312
231
  # collection has not been loaded, it is equivalent to
313
- # <tt>collection.exists?</tt>. If the collection has not already been
232
+ # <tt>!collection.exists?</tt>. If the collection has not already been
314
233
  # loaded and you are going to fetch the records anyway it is better to
315
234
  # check <tt>collection.length.zero?</tt>.
316
235
  def empty?
317
- if loaded?
236
+ if loaded? || @association_ids || reflection.has_cached_counter?
318
237
  size.zero?
319
238
  else
320
- @target.blank? && !scope.exists?
239
+ target.empty? && !scope.exists?
321
240
  end
322
241
  end
323
242
 
324
- # Returns true if the collections is not empty.
325
- # Equivalent to +!collection.empty?+.
326
- def any?
327
- if block_given?
328
- load_target.any? { |*block_args| yield(*block_args) }
329
- else
330
- !empty?
331
- end
332
- end
333
-
334
- # Returns true if the collection has more than 1 record.
335
- # Equivalent to +collection.size > 1+.
336
- def many?
337
- if block_given?
338
- load_target.many? { |*block_args| yield(*block_args) }
339
- else
340
- size > 1
341
- end
342
- end
343
-
344
- def distinct
345
- seen = {}
346
- load_target.find_all do |record|
347
- seen[record.id] = true unless seen.key?(record.id)
348
- end
349
- end
350
- alias uniq distinct
351
-
352
243
  # Replace this collection with +other_array+. This will perform a diff
353
244
  # and delete/add only records that have changed.
354
245
  def replace(other_array)
@@ -361,6 +252,8 @@ module ActiveRecord
361
252
  replace_common_records_in_memory(other_array, original_target)
362
253
  if other_array != original_target
363
254
  transaction { replace_records(other_array, original_target) }
255
+ else
256
+ other_array
364
257
  end
365
258
  end
366
259
  end
@@ -386,32 +279,24 @@ module ActiveRecord
386
279
  target
387
280
  end
388
281
 
389
- def add_to_target(record, skip_callbacks = false, &block)
390
- if association_scope.distinct_value
391
- index = @target.index(record)
392
- end
393
- replace_on_target(record, index, skip_callbacks, &block)
282
+ def add_to_target(record, skip_callbacks: false, replace: false, &block)
283
+ replace_on_target(record, skip_callbacks, replace: replace || association_scope.distinct_value, &block)
394
284
  end
395
285
 
396
- def replace_on_target(record, index, skip_callbacks)
397
- callback(:before_add, record) unless skip_callbacks
398
- yield(record) if block_given?
286
+ def target=(record)
287
+ return super unless ActiveRecord::Base.has_many_inversing
399
288
 
400
- if index
401
- @target[index] = record
289
+ case record
290
+ when Array
291
+ super
402
292
  else
403
- @target << record
293
+ replace_on_target(record, true, replace: true, inversing: true)
404
294
  end
405
-
406
- callback(:after_add, record) unless skip_callbacks
407
- set_inverse_instance(record)
408
-
409
- record
410
295
  end
411
296
 
412
- def scope(opts = {})
413
- scope = super()
414
- scope.none! if opts.fetch(:nullify, true) && null_scope?
297
+ def scope
298
+ scope = super
299
+ scope.none! if null_scope?
415
300
  scope
416
301
  end
417
302
 
@@ -419,34 +304,15 @@ module ActiveRecord
419
304
  owner.new_record? && !foreign_key_present?
420
305
  end
421
306
 
422
- private
423
- def get_records
424
- if reflection.scope_chain.any?(&:any?) ||
425
- scope.eager_loading? ||
426
- klass.current_scope ||
427
- klass.default_scopes.any?
428
-
429
- return scope.to_a
430
- end
431
-
432
- conn = klass.connection
433
- sc = reflection.association_scope_cache(conn, owner) do
434
- StatementCache.create(conn) { |params|
435
- as = AssociationScope.create { params.bind }
436
- target_scope.merge as.scope(self, conn)
437
- }
438
- end
439
-
440
- binds = AssociationScope.get_bind_values(owner, reflection.chain)
441
- sc.execute binds, klass, klass.connection
307
+ def find_from_target?
308
+ loaded? ||
309
+ owner.strict_loading? ||
310
+ reflection.strict_loading? ||
311
+ owner.new_record? ||
312
+ target.any? { |record| record.new_record? || record.changed? }
442
313
  end
443
314
 
444
- def find_target
445
- records = get_records
446
- records.each { |record| set_inverse_instance(record) }
447
- records
448
- end
449
-
315
+ private
450
316
  # We have some records loaded from the database (persisted) and some that are
451
317
  # in-memory (memory). The same record may be represented in the persisted array
452
318
  # and in the memory array.
@@ -464,7 +330,7 @@ module ActiveRecord
464
330
  persisted.map! do |record|
465
331
  if mem_record = memory.delete(record)
466
332
 
467
- ((record.attribute_names & mem_record.attribute_names) - mem_record.changes.keys).each do |name|
333
+ ((record.attribute_names & mem_record.attribute_names) - mem_record.changed_attribute_names_to_save).each do |name|
468
334
  mem_record[name] = record[name]
469
335
  end
470
336
 
@@ -474,7 +340,7 @@ module ActiveRecord
474
340
  end
475
341
  end
476
342
 
477
- persisted + memory
343
+ persisted + memory.reject(&:persisted?)
478
344
  end
479
345
 
480
346
  def _create_record(attributes, raise = false, &block)
@@ -485,28 +351,35 @@ module ActiveRecord
485
351
  if attributes.is_a?(Array)
486
352
  attributes.collect { |attr| _create_record(attr, raise, &block) }
487
353
  else
354
+ record = build_record(attributes, &block)
488
355
  transaction do
489
- add_to_target(build_record(attributes)) do |record|
490
- yield(record) if block_given?
491
- insert_record(record, true, raise)
356
+ result = nil
357
+ add_to_target(record) do
358
+ result = insert_record(record, true, raise) {
359
+ @_was_loaded = loaded?
360
+ }
492
361
  end
362
+ raise ActiveRecord::Rollback unless result
493
363
  end
364
+ record
494
365
  end
495
366
  end
496
367
 
497
368
  # Do the relevant stuff to insert the given record into the association collection.
498
- def insert_record(record, validate = true, raise = false)
499
- raise NotImplementedError
500
- end
501
-
502
- def create_scope
503
- scope.scope_for_create.stringify_keys
369
+ def insert_record(record, validate = true, raise = false, &block)
370
+ if raise
371
+ record.save!(validate: validate, &block)
372
+ else
373
+ record.save(validate: validate, &block)
374
+ end
504
375
  end
505
376
 
506
377
  def delete_or_destroy(records, method)
378
+ return if records.empty?
379
+ records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
507
380
  records = records.flatten
508
381
  records.each { |record| raise_on_type_mismatch!(record) }
509
- existing_records = records.reject { |r| r.new_record? }
382
+ existing_records = records.reject(&:new_record?)
510
383
 
511
384
  if existing_records.empty?
512
385
  remove_records(existing_records, records, method)
@@ -516,24 +389,28 @@ module ActiveRecord
516
389
  end
517
390
 
518
391
  def remove_records(existing_records, records, method)
519
- records.each { |record| callback(:before_remove, record) }
392
+ catch(:abort) do
393
+ records.each { |record| callback(:before_remove, record) }
394
+ end || return
520
395
 
521
396
  delete_records(existing_records, method) if existing_records.any?
522
- records.each { |record| target.delete(record) }
397
+ @target -= records
398
+ @association_ids = nil
523
399
 
524
400
  records.each { |record| callback(:after_remove, record) }
525
401
  end
526
402
 
527
- # Delete the given records from the association, using one of the methods :destroy,
528
- # :delete_all or :nullify (or nil, in which case a default is used).
403
+ # Delete the given records from the association,
404
+ # using one of the methods +:destroy+, +:delete_all+
405
+ # or +:nullify+ (or +nil+, in which case a default is used).
529
406
  def delete_records(records, method)
530
407
  raise NotImplementedError
531
408
  end
532
409
 
533
410
  def replace_records(new_target, original_target)
534
- delete(target - new_target)
411
+ delete(difference(target, new_target))
535
412
 
536
- unless concat(new_target - target)
413
+ unless concat(difference(new_target, target))
537
414
  @target = original_target
538
415
  raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
539
416
  "new records could not be saved."
@@ -543,24 +420,65 @@ module ActiveRecord
543
420
  end
544
421
 
545
422
  def replace_common_records_in_memory(new_target, original_target)
546
- common_records = new_target & original_target
423
+ common_records = intersection(new_target, original_target)
547
424
  common_records.each do |record|
548
425
  skip_callbacks = true
549
- replace_on_target(record, @target.index(record), skip_callbacks)
426
+ replace_on_target(record, skip_callbacks, replace: true)
550
427
  end
551
428
  end
552
429
 
553
- def concat_records(records, should_raise = false)
430
+ def concat_records(records, raise = false)
554
431
  result = true
555
432
 
556
- records.flatten.each do |record|
433
+ records.each do |record|
557
434
  raise_on_type_mismatch!(record)
558
- add_to_target(record) do |rec|
559
- result &&= insert_record(rec, true, should_raise) unless owner.new_record?
435
+ add_to_target(record) do
436
+ unless owner.new_record?
437
+ result &&= insert_record(record, true, raise) {
438
+ @_was_loaded = loaded?
439
+ }
440
+ end
560
441
  end
561
442
  end
562
443
 
563
- result && records
444
+ raise ActiveRecord::Rollback unless result
445
+
446
+ records
447
+ end
448
+
449
+ def replace_on_target(record, skip_callbacks, replace:, inversing: false)
450
+ if replace && (!record.new_record? || @replaced_or_added_targets.include?(record))
451
+ index = @target.index(record)
452
+ end
453
+
454
+ catch(:abort) do
455
+ callback(:before_add, record)
456
+ end || return unless skip_callbacks
457
+
458
+ set_inverse_instance(record)
459
+
460
+ @_was_loaded = true
461
+
462
+ yield(record) if block_given?
463
+
464
+ if !index && @replaced_or_added_targets.include?(record)
465
+ index = @target.index(record)
466
+ end
467
+
468
+ @replaced_or_added_targets << record if inversing || index || record.new_record?
469
+
470
+ if index
471
+ target[index] = record
472
+ elsif @_was_loaded || !loaded?
473
+ @association_ids = nil
474
+ target << record
475
+ end
476
+
477
+ callback(:after_add, record) unless skip_callbacks
478
+
479
+ record
480
+ ensure
481
+ @_was_loaded = nil
564
482
  end
565
483
 
566
484
  def callback(method, record)
@@ -574,31 +492,12 @@ module ActiveRecord
574
492
  owner.class.send(full_callback_name)
575
493
  end
576
494
 
577
- # Should we deal with assoc.first or assoc.last by issuing an independent query to
578
- # the database, or by getting the target, and then taking the first/last item from that?
579
- #
580
- # If the args is just a non-empty options hash, go to the database.
581
- #
582
- # Otherwise, go to the database only if none of the following are true:
583
- # * target already loaded
584
- # * owner is new record
585
- # * target contains new or changed record(s)
586
- def fetch_first_nth_or_last_using_find?(args)
587
- if args.first.is_a?(Hash)
588
- true
589
- else
590
- !(loaded? ||
591
- owner.new_record? ||
592
- target.any? { |record| record.new_record? || record.changed? })
593
- end
594
- end
595
-
596
495
  def include_in_memory?(record)
597
496
  if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
598
497
  assoc = owner.association(reflection.through_reflection.name)
599
498
  assoc.reader.any? { |source|
600
- target = source.send(reflection.source_reflection.name)
601
- target.respond_to?(:include?) ? target.include?(record) : target == record
499
+ target_reflection = source.send(reflection.source_reflection.name)
500
+ target_reflection.respond_to?(:include?) ? target_reflection.include?(record) : target_reflection == record
602
501
  } || target.include?(record)
603
502
  else
604
503
  target.include?(record)
@@ -609,7 +508,7 @@ module ActiveRecord
609
508
  # specified, then #find scans the entire collection.
610
509
  def find_by_scan(*args)
611
510
  expects_array = args.first.kind_of?(Array)
612
- ids = args.flatten.compact.map{ |arg| arg.to_s }.uniq
511
+ ids = args.flatten.compact.map(&:to_s).uniq
613
512
 
614
513
  if ids.size == 1
615
514
  id = ids.first
@@ -619,16 +518,6 @@ module ActiveRecord
619
518
  load_target.select { |r| ids.include?(r.id.to_s) }
620
519
  end
621
520
  end
622
-
623
- # Fetches the first/last using SQL if possible, otherwise from the target array.
624
- def first_nth_or_last(type, *args)
625
- args.shift if args.first.is_a?(Hash) && args.first.empty?
626
-
627
- collection = fetch_first_nth_or_last_using_find?(args) ? scope : load_target
628
- collection.send(type, *args).tap do |record|
629
- set_inverse_instance record if record.is_a? ActiveRecord::Base
630
- end
631
- end
632
521
  end
633
522
  end
634
523
  end