activerecord 5.0.7.2 → 6.0.3.4

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 (359) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +708 -2040
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +9 -7
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -22
  8. data/lib/active_record/advisory_lock_base.rb +18 -0
  9. data/lib/active_record/aggregations.rb +249 -247
  10. data/lib/active_record/association_relation.rb +18 -14
  11. data/lib/active_record/associations.rb +1603 -1592
  12. data/lib/active_record/associations/alias_tracker.rb +24 -34
  13. data/lib/active_record/associations/association.rb +114 -55
  14. data/lib/active_record/associations/association_scope.rb +94 -94
  15. data/lib/active_record/associations/belongs_to_association.rb +58 -42
  16. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  17. data/lib/active_record/associations/builder/association.rb +18 -25
  18. data/lib/active_record/associations/builder/belongs_to.rb +43 -54
  19. data/lib/active_record/associations/builder/collection_association.rb +7 -18
  20. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +41 -62
  21. data/lib/active_record/associations/builder/has_many.rb +4 -0
  22. data/lib/active_record/associations/builder/has_one.rb +37 -1
  23. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  24. data/lib/active_record/associations/collection_association.rb +86 -254
  25. data/lib/active_record/associations/collection_proxy.rb +158 -122
  26. data/lib/active_record/associations/foreign_association.rb +9 -0
  27. data/lib/active_record/associations/has_many_association.rb +23 -30
  28. data/lib/active_record/associations/has_many_through_association.rb +58 -44
  29. data/lib/active_record/associations/has_one_association.rb +59 -54
  30. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  31. data/lib/active_record/associations/join_dependency.rb +143 -176
  32. data/lib/active_record/associations/join_dependency/join_association.rb +38 -87
  33. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  34. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  35. data/lib/active_record/associations/preloader.rb +90 -103
  36. data/lib/active_record/associations/preloader/association.rb +86 -100
  37. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  38. data/lib/active_record/associations/singular_association.rb +12 -45
  39. data/lib/active_record/associations/through_association.rb +26 -14
  40. data/lib/active_record/attribute_assignment.rb +54 -61
  41. data/lib/active_record/attribute_decorators.rb +38 -17
  42. data/lib/active_record/attribute_methods.rb +66 -106
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -8
  44. data/lib/active_record/attribute_methods/dirty.rb +179 -109
  45. data/lib/active_record/attribute_methods/primary_key.rb +85 -92
  46. data/lib/active_record/attribute_methods/query.rb +4 -3
  47. data/lib/active_record/attribute_methods/read.rb +20 -49
  48. data/lib/active_record/attribute_methods/serialization.rb +29 -7
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -66
  50. data/lib/active_record/attribute_methods/write.rb +34 -33
  51. data/lib/active_record/attributes.rb +38 -25
  52. data/lib/active_record/autosave_association.rb +54 -35
  53. data/lib/active_record/base.rb +27 -24
  54. data/lib/active_record/callbacks.rb +64 -35
  55. data/lib/active_record/coders/json.rb +2 -0
  56. data/lib/active_record/coders/yaml_column.rb +11 -12
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +552 -323
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +215 -94
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -35
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -28
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +228 -147
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +400 -213
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -79
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -202
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +396 -562
  70. data/lib/active_record/connection_adapters/column.rb +41 -13
  71. data/lib/active_record/connection_adapters/connection_specification.rb +172 -139
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
  73. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +137 -49
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +48 -30
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +19 -31
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -54
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  101. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -31
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +8 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +20 -26
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +378 -308
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +383 -275
  118. data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
  120. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  121. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  122. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  123. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
  124. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  127. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +259 -266
  128. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  129. data/lib/active_record/connection_handling.rb +143 -40
  130. data/lib/active_record/core.rb +201 -163
  131. data/lib/active_record/counter_cache.rb +60 -28
  132. data/lib/active_record/database_configurations.rb +233 -0
  133. data/lib/active_record/database_configurations/database_config.rb +37 -0
  134. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  135. data/lib/active_record/database_configurations/url_config.rb +78 -0
  136. data/lib/active_record/define_callbacks.rb +22 -0
  137. data/lib/active_record/dynamic_matchers.rb +87 -87
  138. data/lib/active_record/enum.rb +60 -23
  139. data/lib/active_record/errors.rb +114 -18
  140. data/lib/active_record/explain.rb +4 -4
  141. data/lib/active_record/explain_registry.rb +3 -1
  142. data/lib/active_record/explain_subscriber.rb +9 -4
  143. data/lib/active_record/fixture_set/file.rb +13 -8
  144. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  145. data/lib/active_record/fixture_set/render_context.rb +17 -0
  146. data/lib/active_record/fixture_set/table_row.rb +152 -0
  147. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  148. data/lib/active_record/fixtures.rb +194 -504
  149. data/lib/active_record/gem_version.rb +5 -3
  150. data/lib/active_record/inheritance.rb +150 -99
  151. data/lib/active_record/insert_all.rb +179 -0
  152. data/lib/active_record/integration.rb +116 -25
  153. data/lib/active_record/internal_metadata.rb +16 -19
  154. data/lib/active_record/legacy_yaml_adapter.rb +4 -2
  155. data/lib/active_record/locking/optimistic.rb +77 -87
  156. data/lib/active_record/locking/pessimistic.rb +18 -6
  157. data/lib/active_record/log_subscriber.rb +48 -29
  158. data/lib/active_record/middleware/database_selector.rb +74 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +369 -302
  162. data/lib/active_record/migration/command_recorder.rb +134 -100
  163. data/lib/active_record/migration/compatibility.rb +174 -56
  164. data/lib/active_record/migration/join_table.rb +8 -7
  165. data/lib/active_record/model_schema.rb +131 -127
  166. data/lib/active_record/nested_attributes.rb +213 -202
  167. data/lib/active_record/no_touching.rb +12 -3
  168. data/lib/active_record/null_relation.rb +12 -34
  169. data/lib/active_record/persistence.rb +446 -77
  170. data/lib/active_record/query_cache.rb +13 -12
  171. data/lib/active_record/querying.rb +37 -24
  172. data/lib/active_record/railtie.rb +128 -36
  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 +312 -177
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +214 -252
  179. data/lib/active_record/relation.rb +440 -318
  180. data/lib/active_record/relation/batches.rb +98 -52
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
  182. data/lib/active_record/relation/calculations.rb +212 -173
  183. data/lib/active_record/relation/delegation.rb +72 -69
  184. data/lib/active_record/relation/finder_methods.rb +207 -247
  185. data/lib/active_record/relation/from_clause.rb +6 -8
  186. data/lib/active_record/relation/merger.rb +78 -62
  187. data/lib/active_record/relation/predicate_builder.rb +83 -105
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  195. data/lib/active_record/relation/query_attribute.rb +33 -2
  196. data/lib/active_record/relation/query_methods.rb +476 -334
  197. data/lib/active_record/relation/record_fetch_warning.rb +5 -3
  198. data/lib/active_record/relation/spawn_methods.rb +8 -8
  199. data/lib/active_record/relation/where_clause.rb +111 -96
  200. data/lib/active_record/relation/where_clause_factory.rb +6 -11
  201. data/lib/active_record/result.rb +69 -40
  202. data/lib/active_record/runtime_registry.rb +5 -3
  203. data/lib/active_record/sanitization.rb +83 -99
  204. data/lib/active_record/schema.rb +7 -14
  205. data/lib/active_record/schema_dumper.rb +71 -69
  206. data/lib/active_record/schema_migration.rb +16 -6
  207. data/lib/active_record/scoping.rb +20 -20
  208. data/lib/active_record/scoping/default.rb +92 -95
  209. data/lib/active_record/scoping/named.rb +47 -27
  210. data/lib/active_record/secure_token.rb +4 -2
  211. data/lib/active_record/serialization.rb +2 -0
  212. data/lib/active_record/statement_cache.rb +63 -28
  213. data/lib/active_record/store.rb +121 -41
  214. data/lib/active_record/suppressor.rb +6 -3
  215. data/lib/active_record/table_metadata.rb +39 -18
  216. data/lib/active_record/tasks/database_tasks.rb +271 -81
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +54 -91
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +77 -47
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +33 -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 +70 -36
  223. data/lib/active_record/touch_later.rb +8 -6
  224. data/lib/active_record/transactions.rb +141 -157
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type.rb +23 -18
  227. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  228. data/lib/active_record/type/date.rb +2 -0
  229. data/lib/active_record/type/date_time.rb +2 -0
  230. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  231. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  232. data/lib/active_record/type/internal/timezone.rb +2 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +16 -9
  235. data/lib/active_record/type/text.rb +11 -0
  236. data/lib/active_record/type/time.rb +2 -1
  237. data/lib/active_record/type/type_map.rb +14 -17
  238. data/lib/active_record/type/unsigned_integer.rb +16 -0
  239. data/lib/active_record/type_caster.rb +4 -2
  240. data/lib/active_record/type_caster/connection.rb +17 -12
  241. data/lib/active_record/type_caster/map.rb +5 -4
  242. data/lib/active_record/validations.rb +7 -5
  243. data/lib/active_record/validations/absence.rb +2 -0
  244. data/lib/active_record/validations/associated.rb +4 -3
  245. data/lib/active_record/validations/length.rb +2 -0
  246. data/lib/active_record/validations/presence.rb +4 -2
  247. data/lib/active_record/validations/uniqueness.rb +29 -42
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/arel.rb +62 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +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.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +203 -0
  317. data/lib/arel/visitors/dot.rb +296 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +156 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +158 -0
  323. data/lib/arel/visitors/oracle12.rb +65 -0
  324. data/lib/arel/visitors/postgresql.rb +109 -0
  325. data/lib/arel/visitors/sqlite.rb +38 -0
  326. data/lib/arel/visitors/to_sql.rb +888 -0
  327. data/lib/arel/visitors/visitor.rb +45 -0
  328. data/lib/arel/visitors/where_sql.rb +22 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +7 -5
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  332. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  333. data/lib/rails/generators/active_record/migration.rb +17 -3
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
  335. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
  336. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
  337. data/lib/rails/generators/active_record/model/model_generator.rb +9 -30
  338. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  339. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  340. metadata +137 -52
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  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 -15
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  348. data/lib/active_record/attribute.rb +0 -213
  349. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  355. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  356. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  357. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  358. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  359. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,38 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasAndBelongsToMany # :nodoc:
3
- class JoinTableResolver # :nodoc:
4
- KnownTable = Struct.new :join_table
5
-
6
- class KnownClass # :nodoc:
7
- def initialize(lhs_class, rhs_class_name)
8
- @lhs_class = lhs_class
9
- @rhs_class_name = rhs_class_name
10
- @join_table = nil
11
- end
12
-
13
- def join_table
14
- @join_table ||= [@lhs_class.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
15
- end
16
-
17
- private
18
-
19
- def klass
20
- @lhs_class.send(:compute_type, @rhs_class_name)
21
- end
22
- end
23
-
24
- def self.build(lhs_class, name, options)
25
- if options[:join_table]
26
- KnownTable.new options[:join_table].to_s
27
- else
28
- class_name = options.fetch(:class_name) {
29
- name.to_s.camelize.singularize
30
- }
31
- KnownClass.new lhs_class, class_name
32
- end
33
- end
34
- end
35
-
36
5
  attr_reader :lhs_model, :association_name, :options
37
6
 
38
7
  def initialize(association_name, lhs_model, options)
@@ -42,10 +11,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
42
11
  end
43
12
 
44
13
  def through_model
45
- habtm = JoinTableResolver.build lhs_model, association_name, options
46
-
47
14
  join_model = Class.new(ActiveRecord::Base) {
48
- class << self;
15
+ class << self
49
16
  attr_accessor :left_model
50
17
  attr_accessor :name
51
18
  attr_accessor :table_name_resolver
@@ -54,7 +21,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
54
21
  end
55
22
 
56
23
  def self.table_name
57
- table_name_resolver.join_table
24
+ # Table name needs to be resolved lazily
25
+ # because RHS class might not have been loaded
26
+ @table_name ||= table_name_resolver.call
58
27
  end
59
28
 
60
29
  def self.compute_type(class_name)
@@ -77,14 +46,13 @@ module ActiveRecord::Associations::Builder # :nodoc:
77
46
  end
78
47
 
79
48
  private
80
-
81
- def self.suppress_composite_primary_key(pk)
82
- pk unless pk.is_a?(Array)
83
- end
49
+ def self.suppress_composite_primary_key(pk)
50
+ pk unless pk.is_a?(Array)
51
+ end
84
52
  }
85
53
 
86
54
  join_model.name = "HABTM_#{association_name.to_s.camelize}"
87
- join_model.table_name_resolver = habtm
55
+ join_model.table_name_resolver = -> { table_name }
88
56
  join_model.left_model = lhs_model
89
57
 
90
58
  join_model.add_left_association :left_side, anonymous_class: lhs_model
@@ -94,7 +62,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
94
62
 
95
63
  def middle_reflection(join_model)
96
64
  middle_name = [lhs_model.name.downcase.pluralize,
97
- association_name].join('_'.freeze).gsub('::'.freeze, '_'.freeze).to_sym
65
+ association_name.to_s].sort.join("_").gsub("::", "_").to_sym
98
66
  middle_options = middle_options join_model
99
67
 
100
68
  HasMany.create_reflection(lhs_model,
@@ -104,30 +72,41 @@ module ActiveRecord::Associations::Builder # :nodoc:
104
72
  end
105
73
 
106
74
  private
75
+ def middle_options(join_model)
76
+ middle_options = {}
77
+ middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
78
+ middle_options[:source] = join_model.left_reflection.name
79
+ if options.key? :foreign_key
80
+ middle_options[:foreign_key] = options[:foreign_key]
81
+ end
82
+ middle_options
83
+ end
107
84
 
108
- def middle_options(join_model)
109
- middle_options = {}
110
- middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
111
- middle_options[:source] = join_model.left_reflection.name
112
- if options.key? :foreign_key
113
- middle_options[:foreign_key] = options[:foreign_key]
85
+ def table_name
86
+ if options[:join_table]
87
+ options[:join_table].to_s
88
+ else
89
+ class_name = options.fetch(:class_name) {
90
+ association_name.to_s.camelize.singularize
91
+ }
92
+ klass = lhs_model.send(:compute_type, class_name.to_s)
93
+ [lhs_model.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
94
+ end
114
95
  end
115
- middle_options
116
- end
117
96
 
118
- def belongs_to_options(options)
119
- rhs_options = {}
97
+ def belongs_to_options(options)
98
+ rhs_options = {}
120
99
 
121
- if options.key? :class_name
122
- rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
123
- rhs_options[:class_name] = options[:class_name]
124
- end
100
+ if options.key? :class_name
101
+ rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
102
+ rhs_options[:class_name] = options[:class_name]
103
+ end
125
104
 
126
- if options.key? :association_foreign_key
127
- rhs_options[:foreign_key] = options[:association_foreign_key]
128
- end
105
+ if options.key? :association_foreign_key
106
+ rhs_options[:foreign_key] = options[:association_foreign_key]
107
+ end
129
108
 
130
- rhs_options
131
- end
109
+ rhs_options
110
+ end
132
111
  end
133
112
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasMany < CollectionAssociation #:nodoc:
3
5
  def self.macro
@@ -11,5 +13,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
11
13
  def self.valid_dependent_options
12
14
  [:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception]
13
15
  end
16
+
17
+ private_class_method :macro, :valid_options, :valid_dependent_options
14
18
  end
15
19
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasOne < SingularAssociation #:nodoc:
3
5
  def self.macro
@@ -5,7 +7,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
5
7
  end
6
8
 
7
9
  def self.valid_options(options)
8
- valid = super + [:as]
10
+ valid = super + [:as, :touch]
9
11
  valid += [:through, :source, :source_type] if options[:through]
10
12
  valid
11
13
  end
@@ -14,6 +16,11 @@ module ActiveRecord::Associations::Builder # :nodoc:
14
16
  [:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
15
17
  end
16
18
 
19
+ def self.define_callbacks(model, reflection)
20
+ super
21
+ add_touch_callbacks(model, reflection) if reflection.options[:touch]
22
+ end
23
+
17
24
  def self.add_destroy_callbacks(model, reflection)
18
25
  super unless reflection.options[:through]
19
26
  end
@@ -24,5 +31,34 @@ module ActiveRecord::Associations::Builder # :nodoc:
24
31
  model.validates_presence_of reflection.name, message: :required
25
32
  end
26
33
  end
34
+
35
+ def self.touch_record(o, name, touch)
36
+ record = o.send name
37
+
38
+ return unless record && record.persisted?
39
+
40
+ if touch != true
41
+ record.touch(touch)
42
+ else
43
+ record.touch
44
+ end
45
+ end
46
+
47
+ def self.add_touch_callbacks(model, reflection)
48
+ name = reflection.name
49
+ touch = reflection.options[:touch]
50
+
51
+ callback = lambda { |record|
52
+ HasOne.touch_record(record, name, touch)
53
+ }
54
+
55
+ model.after_create callback, if: :saved_changes?
56
+ model.after_update callback, if: :saved_changes?
57
+ model.after_destroy callback
58
+ model.after_touch callback
59
+ end
60
+
61
+ private_class_method :macro, :valid_options, :valid_dependent_options, :add_destroy_callbacks,
62
+ :define_callbacks, :define_validations, :add_touch_callbacks
27
63
  end
28
64
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This class is inherited by the has_one and belongs_to association classes
2
4
 
3
5
  module ActiveRecord::Associations::Builder # :nodoc:
@@ -36,5 +38,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
36
38
  end
37
39
  CODE
38
40
  end
41
+
42
+ private_class_method :valid_options, :define_accessors, :define_constructors
39
43
  end
40
44
  end
@@ -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,18 +26,9 @@ 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
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
32
- Passing an argument to force an association to reload is now
33
- deprecated and will be removed in Rails 5.1. Please call `reload`
34
- on the result collection proxy instead.
35
- MSG
36
-
37
- klass.uncached { reload }
38
- elsif stale_target?
30
+ def reader
31
+ if stale_target?
39
32
  reload
40
33
  end
41
34
 
@@ -51,30 +44,29 @@ module ActiveRecord
51
44
  # Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
52
45
  def ids_reader
53
46
  if loaded?
54
- load_target.map do |record|
55
- record.send(reflection.association_primary_key)
56
- end
47
+ target.pluck(reflection.association_primary_key)
48
+ elsif !target.empty?
49
+ load_target.pluck(reflection.association_primary_key)
57
50
  else
58
- @association_ids ||= (
59
- column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
60
- scope.pluck(column)
61
- )
51
+ @association_ids ||= scope.pluck(reflection.association_primary_key)
62
52
  end
63
53
  end
64
54
 
65
55
  # Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
66
56
  def ids_writer(ids)
67
- pk_type = reflection.association_primary_key_type
57
+ primary_key = reflection.association_primary_key
58
+ pk_type = klass.type_for_attribute(primary_key)
68
59
  ids = Array(ids).reject(&:blank?)
69
60
  ids.map! { |i| pk_type.cast(i) }
70
61
 
71
- primary_key = reflection.association_primary_key
72
62
  records = klass.where(primary_key => ids).index_by do |r|
73
63
  r.public_send(primary_key)
74
64
  end.values_at(*ids).compact
75
65
 
76
66
  if records.size != ids.size
77
- klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key)
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)
78
70
  else
79
71
  replace(records)
80
72
  end
@@ -83,80 +75,29 @@ module ActiveRecord
83
75
  def reset
84
76
  super
85
77
  @target = []
86
- end
87
-
88
- def select(*fields)
89
- if block_given?
90
- load_target.select.each { |e| yield e }
91
- else
92
- scope.select(*fields)
93
- end
78
+ @association_ids = nil
94
79
  end
95
80
 
96
81
  def find(*args)
97
- if block_given?
98
- load_target.find(*args) { |*block_args| yield(*block_args) }
99
- else
100
- if options[:inverse_of] && loaded?
101
- args_flatten = args.flatten
102
- raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args_flatten.blank?
103
- result = find_by_scan(*args)
104
-
105
- result_size = Array(result).size
106
- if !result || result_size != args_flatten.size
107
- scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
108
- else
109
- result
110
- end
111
- else
112
- scope.find(*args)
113
- end
114
- end
115
- end
116
-
117
- def first(*args)
118
- first_nth_or_last(:first, *args)
119
- end
120
-
121
- def second(*args)
122
- first_nth_or_last(:second, *args)
123
- end
124
-
125
- def third(*args)
126
- first_nth_or_last(:third, *args)
127
- end
128
-
129
- def fourth(*args)
130
- first_nth_or_last(:fourth, *args)
131
- end
132
-
133
- def fifth(*args)
134
- first_nth_or_last(:fifth, *args)
135
- end
136
-
137
- def forty_two(*args)
138
- first_nth_or_last(:forty_two, *args)
139
- end
140
-
141
- def third_to_last(*args)
142
- first_nth_or_last(:third_to_last, *args)
143
- end
82
+ if options[:inverse_of] && loaded?
83
+ args_flatten = args.flatten
84
+ model = scope.klass
144
85
 
145
- def second_to_last(*args)
146
- first_nth_or_last(:second_to_last, *args)
147
- 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
148
90
 
149
- def last(*args)
150
- first_nth_or_last(:last, *args)
151
- end
91
+ result = find_by_scan(*args)
152
92
 
153
- def take(n = nil)
154
- if loaded?
155
- n ? target.take(n) : target.first
156
- else
157
- scope.take(n).tap do |record|
158
- 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
159
98
  end
99
+ else
100
+ scope.find(*args)
160
101
  end
161
102
  end
162
103
 
@@ -164,23 +105,12 @@ module ActiveRecord
164
105
  if attributes.is_a?(Array)
165
106
  attributes.collect { |attr| build(attr, &block) }
166
107
  else
167
- add_to_target(build_record(attributes)) do |record|
168
- yield(record) if block_given?
169
- end
108
+ add_to_target(build_record(attributes, &block))
170
109
  end
171
110
  end
172
111
 
173
- def create(attributes = {}, &block)
174
- _create_record(attributes, &block)
175
- end
176
-
177
- def create!(attributes = {}, &block)
178
- _create_record(attributes, true, &block)
179
- end
180
-
181
- # Add +records+ to this association. Returns +self+ so method calls may
182
- # be chained. Since << flattens its argument list and inserts each record,
183
- # +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.
184
114
  def concat(*records)
185
115
  records = records.flatten
186
116
  if owner.new_record?
@@ -225,12 +155,12 @@ module ActiveRecord
225
155
  end
226
156
 
227
157
  dependent = if dependent
228
- dependent
229
- elsif options[:dependent] == :destroy
230
- :delete_all
231
- else
232
- options[:dependent]
233
- end
158
+ dependent
159
+ elsif options[:dependent] == :destroy
160
+ :delete_all
161
+ else
162
+ options[:dependent]
163
+ end
234
164
 
235
165
  delete_or_nullify_all_records(dependent).tap do
236
166
  reset
@@ -248,28 +178,6 @@ module ActiveRecord
248
178
  end
249
179
  end
250
180
 
251
- # Count all records using SQL. Construct options and pass them with
252
- # scope to the target class's +count+.
253
- def count(column_name = nil)
254
- relation = scope
255
- if association_scope.distinct_value
256
- # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
257
- column_name ||= reflection.klass.primary_key
258
- relation = relation.distinct
259
- end
260
-
261
- value = relation.count(column_name)
262
-
263
- limit = options[:limit]
264
- offset = options[:offset]
265
-
266
- if limit || offset
267
- [ [value - offset.to_i, 0].max, limit.to_i ].min
268
- else
269
- value
270
- end
271
- end
272
-
273
181
  # Removes +records+ from this association calling +before_remove+ and
274
182
  # +after_remove+ callbacks.
275
183
  #
@@ -278,12 +186,7 @@ module ActiveRecord
278
186
  # are actually removed from the database, that depends precisely on
279
187
  # +delete_records+. They are in any case removed from the collection.
280
188
  def delete(*records)
281
- return if records.empty?
282
- _options = records.extract_options!
283
- dependent = _options[:dependent] || options[:dependent]
284
-
285
- records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
286
- delete_or_destroy(records, dependent)
189
+ delete_or_destroy(records, options[:dependent])
287
190
  end
288
191
 
289
192
  # Deletes the +records+ and removes them from this association calling
@@ -292,8 +195,6 @@ module ActiveRecord
292
195
  # Note that this method removes records from the database ignoring the
293
196
  # +:dependent+ option.
294
197
  def destroy(*records)
295
- return if records.empty?
296
- records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
297
198
  delete_or_destroy(records, :destroy)
298
199
  end
299
200
 
@@ -309,14 +210,12 @@ module ActiveRecord
309
210
  # +count_records+, which is a method descendants have to provide.
310
211
  def size
311
212
  if !find_target? || loaded?
312
- if association_scope.distinct_value
313
- target.uniq.size
314
- else
315
- target.size
316
- end
213
+ target.size
214
+ elsif @association_ids
215
+ @association_ids.size
317
216
  elsif !association_scope.group_values.empty?
318
217
  load_target.size
319
- elsif !association_scope.distinct_value && target.is_a?(Array)
218
+ elsif !association_scope.distinct_value && !target.empty?
320
219
  unsaved_records = target.select(&:new_record?)
321
220
  unsaved_records.size + count_records
322
221
  else
@@ -324,15 +223,6 @@ module ActiveRecord
324
223
  end
325
224
  end
326
225
 
327
- # Returns the size of the collection calling +size+ on the target.
328
- #
329
- # If the collection has been already loaded +length+ and +size+ are
330
- # equivalent. If not and you are going to need the records anyway this
331
- # method will take one less query. Otherwise +size+ is more efficient.
332
- def length
333
- load_target.size
334
- end
335
-
336
226
  # Returns true if the collection is empty.
337
227
  #
338
228
  # If the collection has been loaded
@@ -342,42 +232,12 @@ module ActiveRecord
342
232
  # loaded and you are going to fetch the records anyway it is better to
343
233
  # check <tt>collection.length.zero?</tt>.
344
234
  def empty?
345
- if loaded?
235
+ if loaded? || @association_ids || reflection.has_cached_counter?
346
236
  size.zero?
347
237
  else
348
- @target.blank? && !scope.exists?
349
- end
350
- end
351
-
352
- # Returns true if the collections is not empty.
353
- # If block given, loads all records and checks for one or more matches.
354
- # Otherwise, equivalent to +!collection.empty?+.
355
- def any?
356
- if block_given?
357
- load_target.any? { |*block_args| yield(*block_args) }
358
- else
359
- !empty?
360
- end
361
- end
362
-
363
- # Returns true if the collection has more than 1 record.
364
- # If block given, loads all records and checks for two or more matches.
365
- # Otherwise, equivalent to +collection.size > 1+.
366
- def many?
367
- if block_given?
368
- load_target.many? { |*block_args| yield(*block_args) }
369
- else
370
- size > 1
371
- end
372
- end
373
-
374
- def distinct
375
- seen = {}
376
- load_target.find_all do |record|
377
- seen[record.id] = true unless seen.key?(record.id)
238
+ target.empty? && !scope.exists?
378
239
  end
379
240
  end
380
- alias uniq distinct
381
241
 
382
242
  # Replace this collection with +other_array+. This will perform a diff
383
243
  # and delete/add only records that have changed.
@@ -435,28 +295,13 @@ module ActiveRecord
435
295
  owner.new_record? && !foreign_key_present?
436
296
  end
437
297
 
438
- private
439
- def get_records(&block)
440
- return scope.to_a if skip_statement_cache?
441
-
442
- conn = klass.connection
443
- sc = reflection.association_scope_cache(conn, owner) do
444
- StatementCache.create(conn) { |params|
445
- as = AssociationScope.create { params.bind }
446
- target_scope.merge as.scope(self, conn)
447
- }
448
- end
449
-
450
- binds = AssociationScope.get_bind_values(owner, reflection.chain)
451
- sc.execute(binds, klass, klass.connection, &block)
298
+ def find_from_target?
299
+ loaded? ||
300
+ owner.new_record? ||
301
+ target.any? { |record| record.new_record? || record.changed? }
452
302
  end
453
303
 
454
- def find_target
455
- get_records do |record|
456
- set_inverse_instance(record)
457
- end
458
- end
459
-
304
+ private
460
305
  # We have some records loaded from the database (persisted) and some that are
461
306
  # in-memory (memory). The same record may be represented in the persisted array
462
307
  # and in the memory array.
@@ -474,7 +319,7 @@ module ActiveRecord
474
319
  persisted.map! do |record|
475
320
  if mem_record = memory.delete(record)
476
321
 
477
- ((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|
478
323
  mem_record[name] = record[name]
479
324
  end
480
325
 
@@ -495,12 +340,17 @@ module ActiveRecord
495
340
  if attributes.is_a?(Array)
496
341
  attributes.collect { |attr| _create_record(attr, raise, &block) }
497
342
  else
343
+ record = build_record(attributes, &block)
498
344
  transaction do
499
- add_to_target(build_record(attributes)) do |record|
500
- yield(record) if block_given?
501
- insert_record(record, true, raise) { @_was_loaded = loaded? }
345
+ result = nil
346
+ add_to_target(record) do
347
+ result = insert_record(record, true, raise) {
348
+ @_was_loaded = loaded?
349
+ }
502
350
  end
351
+ raise ActiveRecord::Rollback unless result
503
352
  end
353
+ record
504
354
  end
505
355
  end
506
356
 
@@ -513,11 +363,9 @@ module ActiveRecord
513
363
  end
514
364
  end
515
365
 
516
- def create_scope
517
- scope.scope_for_create.stringify_keys
518
- end
519
-
520
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) }
521
369
  records = records.flatten
522
370
  records.each { |record| raise_on_type_mismatch!(record) }
523
371
  existing_records = records.reject(&:new_record?)
@@ -530,24 +378,28 @@ module ActiveRecord
530
378
  end
531
379
 
532
380
  def remove_records(existing_records, records, method)
533
- records.each { |record| callback(:before_remove, record) }
381
+ catch(:abort) do
382
+ records.each { |record| callback(:before_remove, record) }
383
+ end || return
534
384
 
535
385
  delete_records(existing_records, method) if existing_records.any?
536
- records.each { |record| target.delete(record) }
386
+ @target -= records
387
+ @association_ids = nil
537
388
 
538
389
  records.each { |record| callback(:after_remove, record) }
539
390
  end
540
391
 
541
- # Delete the given records from the association, using one of the methods :destroy,
542
- # :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).
543
395
  def delete_records(records, method)
544
396
  raise NotImplementedError
545
397
  end
546
398
 
547
399
  def replace_records(new_target, original_target)
548
- delete(target - new_target)
400
+ delete(difference(target, new_target))
549
401
 
550
- unless concat(new_target - target)
402
+ unless concat(difference(new_target, target))
551
403
  @target = original_target
552
404
  raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
553
405
  "new records could not be saved."
@@ -557,7 +409,7 @@ module ActiveRecord
557
409
  end
558
410
 
559
411
  def replace_common_records_in_memory(new_target, original_target)
560
- common_records = new_target & original_target
412
+ common_records = intersection(new_target, original_target)
561
413
  common_records.each do |record|
562
414
  skip_callbacks = true
563
415
  replace_on_target(record, @target.index(record), skip_callbacks)
@@ -570,15 +422,23 @@ module ActiveRecord
570
422
  records.each do |record|
571
423
  raise_on_type_mismatch!(record)
572
424
  add_to_target(record) do
573
- result &&= insert_record(record, true, raise) { @_was_loaded = loaded? } unless owner.new_record?
425
+ unless owner.new_record?
426
+ result &&= insert_record(record, true, raise) {
427
+ @_was_loaded = loaded?
428
+ }
429
+ end
574
430
  end
575
431
  end
576
432
 
577
- result && records
433
+ raise ActiveRecord::Rollback unless result
434
+
435
+ records
578
436
  end
579
437
 
580
438
  def replace_on_target(record, index, skip_callbacks)
581
- callback(:before_add, record) unless skip_callbacks
439
+ catch(:abort) do
440
+ callback(:before_add, record)
441
+ end || return unless skip_callbacks
582
442
 
583
443
  set_inverse_instance(record)
584
444
 
@@ -589,6 +449,7 @@ module ActiveRecord
589
449
  if index
590
450
  target[index] = record
591
451
  elsif @_was_loaded || !loaded?
452
+ @association_ids = nil
592
453
  target << record
593
454
  end
594
455
 
@@ -610,25 +471,6 @@ module ActiveRecord
610
471
  owner.class.send(full_callback_name)
611
472
  end
612
473
 
613
- # Should we deal with assoc.first or assoc.last by issuing an independent query to
614
- # the database, or by getting the target, and then taking the first/last item from that?
615
- #
616
- # If the args is just a non-empty options hash, go to the database.
617
- #
618
- # Otherwise, go to the database only if none of the following are true:
619
- # * target already loaded
620
- # * owner is new record
621
- # * target contains new or changed record(s)
622
- def fetch_first_nth_or_last_using_find?(args)
623
- if args.first.is_a?(Hash)
624
- true
625
- else
626
- !(loaded? ||
627
- owner.new_record? ||
628
- target.any? { |record| record.new_record? || record.changed? })
629
- end
630
- end
631
-
632
474
  def include_in_memory?(record)
633
475
  if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
634
476
  assoc = owner.association(reflection.through_reflection.name)
@@ -655,16 +497,6 @@ module ActiveRecord
655
497
  load_target.select { |r| ids.include?(r.id.to_s) }
656
498
  end
657
499
  end
658
-
659
- # Fetches the first/last using SQL if possible, otherwise from the target array.
660
- def first_nth_or_last(type, *args)
661
- args.shift if args.first.is_a?(Hash) && args.first.empty?
662
-
663
- collection = fetch_first_nth_or_last_using_find?(args) ? scope : load_target
664
- collection.send(type, *args).tap do |record|
665
- set_inverse_instance record if record.is_a? ActiveRecord::Base
666
- end
667
- end
668
500
  end
669
501
  end
670
502
  end