activerecord 4.2.11.1 → 6.0.3

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

Potentially problematic release.


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

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