activerecord 4.2.0 → 6.0.5.1

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

Potentially problematic release.


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

Files changed (373) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +852 -801
  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 +267 -249
  9. data/lib/active_record/association_relation.rb +26 -6
  10. data/lib/active_record/associations/alias_tracker.rb +29 -36
  11. data/lib/active_record/associations/association.rb +137 -55
  12. data/lib/active_record/associations/association_scope.rb +110 -132
  13. data/lib/active_record/associations/belongs_to_association.rb +67 -54
  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 -29
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +58 -70
  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 +150 -275
  23. data/lib/active_record/associations/collection_proxy.rb +253 -152
  24. data/lib/active_record/associations/foreign_association.rb +20 -0
  25. data/lib/active_record/associations/has_many_association.rb +35 -84
  26. data/lib/active_record/associations/has_many_through_association.rb +62 -80
  27. data/lib/active_record/associations/has_one_association.rb +62 -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 +43 -78
  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 +159 -162
  33. data/lib/active_record/associations/preloader/association.rb +102 -113
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  35. data/lib/active_record/associations/preloader.rb +96 -95
  36. data/lib/active_record/associations/singular_association.rb +18 -45
  37. data/lib/active_record/associations/through_association.rb +49 -24
  38. data/lib/active_record/associations.rb +1737 -1596
  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 +14 -5
  42. data/lib/active_record/attribute_methods/dirty.rb +174 -134
  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 +61 -37
  48. data/lib/active_record/attribute_methods/write.rb +33 -56
  49. data/lib/active_record/attribute_methods.rb +124 -143
  50. data/lib/active_record/attributes.rb +213 -74
  51. data/lib/active_record/autosave_association.rb +125 -54
  52. data/lib/active_record/base.rb +60 -49
  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 +36 -13
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +810 -291
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +253 -108
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -24
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +171 -53
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -47
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +383 -239
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +736 -235
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +190 -87
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -192
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +536 -600
  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 +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -196
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +71 -115
  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 +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 +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/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 +70 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  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 +465 -291
  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 +565 -363
  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 -364
  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 +277 -233
  130. data/lib/active_record/counter_cache.rb +71 -50
  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 +172 -89
  138. data/lib/active_record/errors.rb +189 -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 +11 -6
  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 +225 -497
  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 +48 -0
  154. data/lib/active_record/locale/en.yml +3 -2
  155. data/lib/active_record/locking/optimistic.rb +99 -98
  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 +636 -290
  165. data/lib/active_record/model_schema.rb +344 -112
  166. data/lib/active_record/nested_attributes.rb +265 -215
  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 +559 -125
  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 +166 -47
  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 +341 -202
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +461 -302
  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 +270 -249
  182. data/lib/active_record/relation/delegation.rb +76 -84
  183. data/lib/active_record/relation/finder_methods.rb +287 -255
  184. data/lib/active_record/relation/from_clause.rb +30 -0
  185. data/lib/active_record/relation/merger.rb +86 -68
  186. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -25
  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 +112 -92
  194. data/lib/active_record/relation/query_attribute.rb +50 -0
  195. data/lib/active_record/relation/query_methods.rb +612 -392
  196. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  197. data/lib/active_record/relation/spawn_methods.rb +18 -17
  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 +533 -340
  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 -20
  207. data/lib/active_record/scoping/default.rb +98 -82
  208. data/lib/active_record/scoping/named.rb +91 -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 +309 -99
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +58 -89
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -31
  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 +243 -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 +222 -146
  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 -41
  228. data/lib/active_record/type/date_time.rb +4 -38
  229. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  230. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  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 +29 -15
  234. data/lib/active_record/type/text.rb +2 -2
  235. data/lib/active_record/type/time.rb +21 -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 +43 -46
  247. data/lib/active_record/validations.rb +38 -35
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/active_record.rb +44 -21
  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 -8
  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.rb +7 -5
  340. metadata +174 -63
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -149
  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/mysql_adapter.rb +0 -491
  352. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  353. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  354. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  355. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  356. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  359. data/lib/active_record/type/big_integer.rb +0 -13
  360. data/lib/active_record/type/binary.rb +0 -50
  361. data/lib/active_record/type/boolean.rb +0 -30
  362. data/lib/active_record/type/decimal.rb +0 -40
  363. data/lib/active_record/type/decorator.rb +0 -14
  364. data/lib/active_record/type/float.rb +0 -19
  365. data/lib/active_record/type/integer.rb +0 -55
  366. data/lib/active_record/type/mutable.rb +0 -16
  367. data/lib/active_record/type/numeric.rb +0 -36
  368. data/lib/active_record/type/string.rb +0 -36
  369. data/lib/active_record/type/time_value.rb +0 -38
  370. data/lib/active_record/type/value.rb +0 -101
  371. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  372. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  373. /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,75 @@ 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).reject(&: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
+ @association_ids = nil
81
79
  end
82
80
 
83
81
  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
82
+ if options[:inverse_of] && loaded?
83
+ args_flatten = args.flatten
84
+ model = scope.klass
115
85
 
116
- def fourth(*args)
117
- first_nth_or_last(:fourth, *args)
118
- end
119
-
120
- def fifth(*args)
121
- first_nth_or_last(:fifth, *args)
122
- 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
123
90
 
124
- def forty_two(*args)
125
- first_nth_or_last(:forty_two, *args)
126
- end
91
+ result = find_by_scan(*args)
127
92
 
128
- def last(*args)
129
- first_nth_or_last(:last, *args)
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
98
+ end
99
+ else
100
+ scope.find(*args)
101
+ end
130
102
  end
131
103
 
132
104
  def build(attributes = {}, &block)
133
105
  if attributes.is_a?(Array)
134
106
  attributes.collect { |attr| build(attr, &block) }
135
107
  else
136
- add_to_target(build_record(attributes)) do |record|
137
- yield(record) if block_given?
138
- end
108
+ add_to_target(build_record(attributes, &block))
139
109
  end
140
110
  end
141
111
 
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.
112
+ # Add +records+ to this association. Since +<<+ flattens its argument list
113
+ # and inserts each record, +push+ and +concat+ behave identically.
153
114
  def concat(*records)
115
+ records = records.flatten
154
116
  if owner.new_record?
155
117
  load_target
156
118
  concat_records(records)
@@ -193,12 +155,12 @@ module ActiveRecord
193
155
  end
194
156
 
195
157
  dependent = if dependent
196
- dependent
197
- elsif options[:dependent] == :destroy
198
- :delete_all
199
- else
200
- options[:dependent]
201
- end
158
+ dependent
159
+ elsif options[:dependent] == :destroy
160
+ :delete_all
161
+ else
162
+ options[:dependent]
163
+ end
202
164
 
203
165
  delete_or_nullify_all_records(dependent).tap do
204
166
  reset
@@ -216,32 +178,6 @@ module ActiveRecord
216
178
  end
217
179
  end
218
180
 
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
181
  # Removes +records+ from this association calling +before_remove+ and
246
182
  # +after_remove+ callbacks.
247
183
  #
@@ -250,12 +186,7 @@ module ActiveRecord
250
186
  # are actually removed from the database, that depends precisely on
251
187
  # +delete_records+. They are in any case removed from the collection.
252
188
  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)
189
+ delete_or_destroy(records, options[:dependent])
259
190
  end
260
191
 
261
192
  # Deletes the +records+ and removes them from this association calling
@@ -264,8 +195,6 @@ module ActiveRecord
264
195
  # Note that this method removes records from the database ignoring the
265
196
  # +:dependent+ option.
266
197
  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
198
  delete_or_destroy(records, :destroy)
270
199
  end
271
200
 
@@ -281,30 +210,19 @@ module ActiveRecord
281
210
  # +count_records+, which is a method descendants have to provide.
282
211
  def size
283
212
  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?
213
+ target.size
214
+ elsif @association_ids
215
+ @association_ids.size
216
+ elsif !association_scope.group_values.empty?
290
217
  load_target.size
291
- elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array)
292
- unsaved_records = target.select { |r| r.new_record? }
218
+ elsif !association_scope.distinct_value && !target.empty?
219
+ unsaved_records = target.select(&:new_record?)
293
220
  unsaved_records.size + count_records
294
221
  else
295
222
  count_records
296
223
  end
297
224
  end
298
225
 
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
226
  # Returns true if the collection is empty.
309
227
  #
310
228
  # If the collection has been loaded
@@ -314,41 +232,13 @@ module ActiveRecord
314
232
  # loaded and you are going to fetch the records anyway it is better to
315
233
  # check <tt>collection.length.zero?</tt>.
316
234
  def empty?
317
- if loaded?
235
+ if loaded? || @association_ids || reflection.has_cached_counter?
318
236
  size.zero?
319
237
  else
320
- @target.blank? && !scope.exists?
238
+ target.empty? && !scope.exists?
321
239
  end
322
240
  end
323
241
 
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
242
  # Replace this collection with +other_array+. This will perform a diff
353
243
  # and delete/add only records that have changed.
354
244
  def replace(other_array)
@@ -361,6 +251,8 @@ module ActiveRecord
361
251
  replace_common_records_in_memory(other_array, original_target)
362
252
  if other_array != original_target
363
253
  transaction { replace_records(other_array, original_target) }
254
+ else
255
+ other_array
364
256
  end
365
257
  end
366
258
  end
@@ -393,25 +285,9 @@ module ActiveRecord
393
285
  replace_on_target(record, index, skip_callbacks, &block)
394
286
  end
395
287
 
396
- def replace_on_target(record, index, skip_callbacks)
397
- callback(:before_add, record) unless skip_callbacks
398
- yield(record) if block_given?
399
-
400
- if index
401
- @target[index] = record
402
- else
403
- @target << record
404
- end
405
-
406
- callback(:after_add, record) unless skip_callbacks
407
- set_inverse_instance(record)
408
-
409
- record
410
- end
411
-
412
- def scope(opts = {})
413
- scope = super()
414
- scope.none! if opts.fetch(:nullify, true) && null_scope?
288
+ def scope
289
+ scope = super
290
+ scope.none! if null_scope?
415
291
  scope
416
292
  end
417
293
 
@@ -419,34 +295,13 @@ module ActiveRecord
419
295
  owner.new_record? && !foreign_key_present?
420
296
  end
421
297
 
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
298
+ def find_from_target?
299
+ loaded? ||
300
+ owner.new_record? ||
301
+ target.any? { |record| record.new_record? || record.changed? }
442
302
  end
443
303
 
444
- def find_target
445
- records = get_records
446
- records.each { |record| set_inverse_instance(record) }
447
- records
448
- end
449
-
304
+ private
450
305
  # We have some records loaded from the database (persisted) and some that are
451
306
  # in-memory (memory). The same record may be represented in the persisted array
452
307
  # and in the memory array.
@@ -464,7 +319,7 @@ module ActiveRecord
464
319
  persisted.map! do |record|
465
320
  if mem_record = memory.delete(record)
466
321
 
467
- ((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|
468
323
  mem_record[name] = record[name]
469
324
  end
470
325
 
@@ -477,6 +332,13 @@ module ActiveRecord
477
332
  persisted + memory
478
333
  end
479
334
 
335
+ def build_record(attributes)
336
+ previous = klass.current_scope(true) if block_given?
337
+ super
338
+ ensure
339
+ klass.current_scope = previous if previous
340
+ end
341
+
480
342
  def _create_record(attributes, raise = false, &block)
481
343
  unless owner.persisted?
482
344
  raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
@@ -485,28 +347,35 @@ module ActiveRecord
485
347
  if attributes.is_a?(Array)
486
348
  attributes.collect { |attr| _create_record(attr, raise, &block) }
487
349
  else
350
+ record = build_record(attributes, &block)
488
351
  transaction do
489
- add_to_target(build_record(attributes)) do |record|
490
- yield(record) if block_given?
491
- insert_record(record, true, raise)
352
+ result = nil
353
+ add_to_target(record) do
354
+ result = insert_record(record, true, raise) {
355
+ @_was_loaded = loaded?
356
+ }
492
357
  end
358
+ raise ActiveRecord::Rollback unless result
493
359
  end
360
+ record
494
361
  end
495
362
  end
496
363
 
497
364
  # 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
365
+ def insert_record(record, validate = true, raise = false, &block)
366
+ if raise
367
+ record.save!(validate: validate, &block)
368
+ else
369
+ record.save(validate: validate, &block)
370
+ end
504
371
  end
505
372
 
506
373
  def delete_or_destroy(records, method)
374
+ return if records.empty?
375
+ records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
507
376
  records = records.flatten
508
377
  records.each { |record| raise_on_type_mismatch!(record) }
509
- existing_records = records.reject { |r| r.new_record? }
378
+ existing_records = records.reject(&:new_record?)
510
379
 
511
380
  if existing_records.empty?
512
381
  remove_records(existing_records, records, method)
@@ -516,24 +385,28 @@ module ActiveRecord
516
385
  end
517
386
 
518
387
  def remove_records(existing_records, records, method)
519
- records.each { |record| callback(:before_remove, record) }
388
+ catch(:abort) do
389
+ records.each { |record| callback(:before_remove, record) }
390
+ end || return
520
391
 
521
392
  delete_records(existing_records, method) if existing_records.any?
522
- records.each { |record| target.delete(record) }
393
+ @target -= records
394
+ @association_ids = nil
523
395
 
524
396
  records.each { |record| callback(:after_remove, record) }
525
397
  end
526
398
 
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).
399
+ # Delete the given records from the association,
400
+ # using one of the methods +:destroy+, +:delete_all+
401
+ # or +:nullify+ (or +nil+, in which case a default is used).
529
402
  def delete_records(records, method)
530
403
  raise NotImplementedError
531
404
  end
532
405
 
533
406
  def replace_records(new_target, original_target)
534
- delete(target - new_target)
407
+ delete(difference(target, new_target))
535
408
 
536
- unless concat(new_target - target)
409
+ unless concat(difference(new_target, target))
537
410
  @target = original_target
538
411
  raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
539
412
  "new records could not be saved."
@@ -543,24 +416,55 @@ module ActiveRecord
543
416
  end
544
417
 
545
418
  def replace_common_records_in_memory(new_target, original_target)
546
- common_records = new_target & original_target
419
+ common_records = intersection(new_target, original_target)
547
420
  common_records.each do |record|
548
421
  skip_callbacks = true
549
422
  replace_on_target(record, @target.index(record), skip_callbacks)
550
423
  end
551
424
  end
552
425
 
553
- def concat_records(records, should_raise = false)
426
+ def concat_records(records, raise = false)
554
427
  result = true
555
428
 
556
- records.flatten.each do |record|
429
+ records.each do |record|
557
430
  raise_on_type_mismatch!(record)
558
- add_to_target(record) do |rec|
559
- result &&= insert_record(rec, true, should_raise) unless owner.new_record?
431
+ add_to_target(record) do
432
+ unless owner.new_record?
433
+ result &&= insert_record(record, true, raise) {
434
+ @_was_loaded = loaded?
435
+ }
436
+ end
560
437
  end
561
438
  end
562
439
 
563
- result && records
440
+ raise ActiveRecord::Rollback unless result
441
+
442
+ records
443
+ end
444
+
445
+ def replace_on_target(record, index, skip_callbacks)
446
+ catch(:abort) do
447
+ callback(:before_add, record)
448
+ end || return unless skip_callbacks
449
+
450
+ set_inverse_instance(record)
451
+
452
+ @_was_loaded = true
453
+
454
+ yield(record) if block_given?
455
+
456
+ if index
457
+ target[index] = record
458
+ elsif @_was_loaded || !loaded?
459
+ @association_ids = nil
460
+ target << record
461
+ end
462
+
463
+ callback(:after_add, record) unless skip_callbacks
464
+
465
+ record
466
+ ensure
467
+ @_was_loaded = nil
564
468
  end
565
469
 
566
470
  def callback(method, record)
@@ -574,31 +478,12 @@ module ActiveRecord
574
478
  owner.class.send(full_callback_name)
575
479
  end
576
480
 
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
481
  def include_in_memory?(record)
597
482
  if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
598
483
  assoc = owner.association(reflection.through_reflection.name)
599
484
  assoc.reader.any? { |source|
600
- target = source.send(reflection.source_reflection.name)
601
- target.respond_to?(:include?) ? target.include?(record) : target == record
485
+ target_reflection = source.send(reflection.source_reflection.name)
486
+ target_reflection.respond_to?(:include?) ? target_reflection.include?(record) : target_reflection == record
602
487
  } || target.include?(record)
603
488
  else
604
489
  target.include?(record)
@@ -609,7 +494,7 @@ module ActiveRecord
609
494
  # specified, then #find scans the entire collection.
610
495
  def find_by_scan(*args)
611
496
  expects_array = args.first.kind_of?(Array)
612
- ids = args.flatten.compact.map{ |arg| arg.to_s }.uniq
497
+ ids = args.flatten.compact.map(&:to_s).uniq
613
498
 
614
499
  if ids.size == 1
615
500
  id = ids.first
@@ -619,16 +504,6 @@ module ActiveRecord
619
504
  load_target.select { |r| ids.include?(r.id.to_s) }
620
505
  end
621
506
  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
507
  end
633
508
  end
634
509
  end