activerecord 4.2.9 → 6.1.4.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 (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +964 -1382
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +266 -251
  8. data/lib/active_record/association_relation.rb +40 -15
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +162 -69
  11. data/lib/active_record/associations/association_scope.rb +105 -130
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -65
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -37
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +49 -66
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +148 -287
  22. data/lib/active_record/associations/collection_proxy.rb +252 -150
  23. data/lib/active_record/associations/foreign_association.rb +23 -1
  24. data/lib/active_record/associations/has_many_association.rb +56 -98
  25. data/lib/active_record/associations/has_many_through_association.rb +68 -89
  26. data/lib/active_record/associations/has_one_association.rb +73 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +174 -169
  32. data/lib/active_record/associations/preloader/association.rb +108 -115
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +97 -94
  35. data/lib/active_record/associations/singular_association.rb +18 -39
  36. data/lib/active_record/associations/through_association.rb +39 -19
  37. data/lib/active_record/associations.rb +1845 -1598
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +18 -10
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -148
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +55 -36
  46. data/lib/active_record/attribute_methods/write.rb +24 -55
  47. data/lib/active_record/attribute_methods.rb +149 -154
  48. data/lib/active_record/attributes.rb +234 -78
  49. data/lib/active_record/autosave_association.rb +133 -60
  50. data/lib/active_record/base.rb +46 -46
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +34 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -323
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +292 -124
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +177 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +8 -6
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +473 -255
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +869 -286
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +257 -91
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +483 -230
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +557 -640
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +194 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +80 -192
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -160
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -58
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -19
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  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 +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +145 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +496 -298
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +588 -375
  119. data/lib/active_record/connection_adapters/schema_cache.rb +167 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -373
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +458 -241
  133. data/lib/active_record/counter_cache.rb +70 -49
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +272 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +211 -92
  143. data/lib/active_record/errors.rb +224 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +10 -5
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +275 -500
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +62 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +27 -5
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +98 -92
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +295 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +673 -325
  170. data/lib/active_record/model_schema.rb +418 -113
  171. data/lib/active_record/nested_attributes.rb +263 -224
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +572 -136
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +170 -51
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +523 -199
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +454 -291
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +324 -249
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +316 -242
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +95 -103
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -26
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +136 -122
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -413
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +18 -20
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -343
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -23
  209. data/lib/active_record/scoping/default.rb +96 -83
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +128 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +364 -130
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +67 -113
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +86 -49
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +287 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +182 -163
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -45
  231. data/lib/active_record/type/date_time.rb +4 -49
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +27 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +63 -56
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +42 -29
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -4
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. data/lib/rails/generators/active_record.rb +7 -5
  340. metadata +172 -65
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -163
  349. data/lib/active_record/attribute_decorators.rb +0 -66
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/attribute_set.rb +0 -81
  352. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  353. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  354. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  355. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  356. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  357. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  358. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  359. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  360. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  361. data/lib/active_record/type/big_integer.rb +0 -13
  362. data/lib/active_record/type/binary.rb +0 -50
  363. data/lib/active_record/type/boolean.rb +0 -31
  364. data/lib/active_record/type/decimal.rb +0 -64
  365. data/lib/active_record/type/decorator.rb +0 -14
  366. data/lib/active_record/type/float.rb +0 -19
  367. data/lib/active_record/type/integer.rb +0 -59
  368. data/lib/active_record/type/mutable.rb +0 -16
  369. data/lib/active_record/type/numeric.rb +0 -36
  370. data/lib/active_record/type/string.rb +0 -40
  371. data/lib/active_record/type/time_value.rb +0 -38
  372. data/lib/active_record/type/value.rb +0 -110
  373. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  374. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations
2
- module ForeignAssociation
4
+ module ForeignAssociation # :nodoc:
3
5
  def foreign_key_present?
4
6
  if reflection.klass.primary_key
5
7
  owner.attribute_present?(reflection.active_record_primary_key)
@@ -7,5 +9,25 @@ module ActiveRecord::Associations
7
9
  false
8
10
  end
9
11
  end
12
+
13
+ def nullified_owner_attributes
14
+ Hash.new.tap do |attrs|
15
+ attrs[reflection.foreign_key] = nil
16
+ attrs[reflection.type] = nil if reflection.type.present?
17
+ end
18
+ end
19
+
20
+ private
21
+ # Sets the owner attributes on the given record
22
+ def set_owner_attributes(record)
23
+ return if options[:through]
24
+
25
+ key = owner._read_attribute(reflection.join_foreign_key)
26
+ record._write_attribute(reflection.join_primary_key, key)
27
+
28
+ if reflection.type
29
+ record._write_attribute(reflection.type, owner.class.polymorphic_name)
30
+ end
31
+ end
10
32
  end
11
33
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Has Many Association
3
4
  module Associations
5
+ # = Active Record Has Many Association
4
6
  # This is the proxy that handles a has many association.
5
7
  #
6
8
  # If the association has a <tt>:through</tt> option further specialization
@@ -15,43 +17,48 @@ module ActiveRecord
15
17
 
16
18
  when :restrict_with_error
17
19
  unless empty?
18
- record = klass.human_attribute_name(reflection.name).downcase
19
- owner.errors.add(:base, :"restrict_dependent_destroy.many", record: record)
20
- false
20
+ record = owner.class.human_attribute_name(reflection.name).downcase
21
+ owner.errors.add(:base, :'restrict_dependent_destroy.has_many', record: record)
22
+ throw(:abort)
21
23
  end
22
24
 
23
- else
24
- if options[:dependent] == :destroy
25
- # No point in executing the counter update since we're going to destroy the parent anyway
26
- load_target.each { |t| t.destroyed_by_association = reflection }
27
- destroy_all
28
- else
29
- delete_all
25
+ when :destroy
26
+ # No point in executing the counter update since we're going to destroy the parent anyway
27
+ load_target.each { |t| t.destroyed_by_association = reflection }
28
+ destroy_all
29
+ when :destroy_async
30
+ load_target.each do |t|
31
+ t.destroyed_by_association = reflection
30
32
  end
31
- end
32
- end
33
33
 
34
- def insert_record(record, validate = true, raise = false)
35
- set_owner_attributes(record)
36
- set_inverse_instance(record)
37
-
38
- if raise
39
- record.save!(:validate => validate)
34
+ unless target.empty?
35
+ association_class = target.first.class
36
+ primary_key_column = association_class.primary_key.to_sym
37
+
38
+ ids = target.collect do |assoc|
39
+ assoc.public_send(primary_key_column)
40
+ end
41
+
42
+ enqueue_destroy_association(
43
+ owner_model_name: owner.class.to_s,
44
+ owner_id: owner.id,
45
+ association_class: reflection.klass.to_s,
46
+ association_ids: ids,
47
+ association_primary_key_column: primary_key_column,
48
+ ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
49
+ )
50
+ end
40
51
  else
41
- record.save(:validate => validate)
52
+ delete_all
42
53
  end
43
54
  end
44
55
 
45
- def empty?
46
- if has_cached_counter?
47
- size.zero?
48
- else
49
- super
50
- end
56
+ def insert_record(record, validate = true, raise = false)
57
+ set_owner_attributes(record)
58
+ super
51
59
  end
52
60
 
53
61
  private
54
-
55
62
  # Returns the number of records in this collection.
56
63
  #
57
64
  # If the association has a counter cache it gets that value. Otherwise
@@ -66,110 +73,53 @@ module ActiveRecord
66
73
  # If the collection is empty the target is set to an empty array and
67
74
  # the loaded flag is set to true as well.
68
75
  def count_records
69
- count = if has_cached_counter?
70
- owner._read_attribute cached_counter_attribute_name
76
+ count = if reflection.has_cached_counter?
77
+ owner.read_attribute(reflection.counter_cache_column).to_i
71
78
  else
72
- scope.count
79
+ scope.count(:all)
73
80
  end
74
81
 
75
82
  # If there's nothing in the database and @target has no new records
76
83
  # we are certain the current target is an empty array. This is a
77
84
  # documented side-effect of the method that may avoid an extra SELECT.
78
- @target ||= [] and loaded! if count == 0
85
+ loaded! if count == 0
79
86
 
80
87
  [association_scope.limit_value, count].compact.min
81
88
  end
82
89
 
83
-
84
- # Returns whether a counter cache should be used for this association.
85
- #
86
- # The counter_cache option must be given on either the owner or inverse
87
- # association, and the column must be present on the owner.
88
- def has_cached_counter?(reflection = reflection())
89
- if reflection.options[:counter_cache] || (inverse = inverse_which_updates_counter_cache(reflection)) && inverse.options[:counter_cache]
90
- owner.attribute_present?(cached_counter_attribute_name(reflection))
91
- end
92
- end
93
-
94
- def cached_counter_attribute_name(reflection = reflection())
95
- if reflection.options[:counter_cache]
96
- reflection.options[:counter_cache].to_s
97
- else
98
- "#{reflection.name}_count"
99
- end
100
- end
101
-
102
90
  def update_counter(difference, reflection = reflection())
103
- update_counter_in_database(difference, reflection)
104
- update_counter_in_memory(difference, reflection)
105
- end
106
-
107
- def update_counter_in_database(difference, reflection = reflection())
108
- if has_cached_counter?(reflection)
109
- counter = cached_counter_attribute_name(reflection)
110
- owner.class.update_counters(owner.id, counter => difference)
91
+ if reflection.has_cached_counter?
92
+ owner.increment!(reflection.counter_cache_column, difference)
111
93
  end
112
94
  end
113
95
 
114
96
  def update_counter_in_memory(difference, reflection = reflection())
115
- if counter_must_be_updated_by_has_many?(reflection)
116
- counter = cached_counter_attribute_name(reflection)
117
- owner[counter] += difference
118
- owner.send(:clear_attribute_changes, counter) # eww
97
+ if reflection.counter_must_be_updated_by_has_many?
98
+ counter = reflection.counter_cache_column
99
+ owner.increment(counter, difference)
100
+ owner.send(:"clear_#{counter}_change")
119
101
  end
120
102
  end
121
103
 
122
- # This shit is nasty. We need to avoid the following situation:
123
- #
124
- # * An associated record is deleted via record.destroy
125
- # * Hence the callbacks run, and they find a belongs_to on the record with a
126
- # :counter_cache options which points back at our owner. So they update the
127
- # counter cache.
128
- # * In which case, we must make sure to *not* update the counter cache, or else
129
- # it will be decremented twice.
130
- #
131
- # Hence this method.
132
- def inverse_which_updates_counter_cache(reflection = reflection())
133
- counter_name = cached_counter_attribute_name(reflection)
134
- inverse_which_updates_counter_named(counter_name, reflection)
135
- end
136
- alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
137
-
138
- def inverse_which_updates_counter_named(counter_name, reflection)
139
- reflection.klass._reflections.values.find { |inverse_reflection|
140
- inverse_reflection.belongs_to? &&
141
- inverse_reflection.counter_cache_column == counter_name
142
- }
143
- end
144
- alias inverse_updates_counter_named? inverse_which_updates_counter_named
145
-
146
- def inverse_updates_counter_in_memory?(reflection)
147
- inverse = inverse_which_updates_counter_cache(reflection)
148
- inverse && inverse == reflection.inverse_of
149
- end
150
-
151
- def counter_must_be_updated_by_has_many?(reflection)
152
- !inverse_updates_counter_in_memory?(reflection) && has_cached_counter?(reflection)
153
- end
154
-
155
104
  def delete_count(method, scope)
156
105
  if method == :delete_all
157
106
  scope.delete_all
158
107
  else
159
- scope.update_all(reflection.foreign_key => nil)
108
+ scope.update_all(nullified_owner_attributes)
160
109
  end
161
110
  end
162
111
 
163
112
  def delete_or_nullify_all_records(method)
164
- count = delete_count(method, self.scope)
113
+ count = delete_count(method, scope)
165
114
  update_counter(-count)
115
+ count
166
116
  end
167
117
 
168
118
  # Deletes the records according to the <tt>:dependent</tt> option.
169
119
  def delete_records(records, method)
170
120
  if method == :destroy
171
121
  records.each(&:destroy!)
172
- update_counter(-records.length) unless inverse_updates_counter_cache?
122
+ update_counter(-records.length) unless reflection.inverse_updates_counter_cache?
173
123
  else
174
124
  scope = self.scope.where(reflection.klass.primary_key => records)
175
125
  update_counter(-delete_count(method, scope))
@@ -194,6 +144,14 @@ module ActiveRecord
194
144
  end
195
145
  saved_successfully
196
146
  end
147
+
148
+ def difference(a, b)
149
+ a - b
150
+ end
151
+
152
+ def intersection(a, b)
153
+ a & b
154
+ end
197
155
  end
198
156
  end
199
157
  end
@@ -1,31 +1,14 @@
1
- require 'active_support/core_ext/string/filters'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- # = Active Record Has Many Through Association
5
4
  module Associations
5
+ # = Active Record Has Many Through Association
6
6
  class HasManyThroughAssociation < HasManyAssociation #:nodoc:
7
7
  include ThroughAssociation
8
8
 
9
9
  def initialize(owner, reflection)
10
10
  super
11
-
12
- @through_records = {}
13
- @through_association = nil
14
- end
15
-
16
- # Returns the size of the collection by executing a SELECT COUNT(*) query
17
- # if the collection hasn't been loaded, and by calling collection.size if
18
- # it has. If the collection will likely have a size greater than zero,
19
- # and if fetching the collection will be needed afterwards, one less
20
- # SELECT query will be generated by using #length instead.
21
- def size
22
- if has_cached_counter?
23
- owner._read_attribute cached_counter_attribute_name(reflection)
24
- elsif loaded?
25
- target.size
26
- else
27
- super
28
- end
11
+ @through_records = {}.compare_by_identity
29
12
  end
30
13
 
31
14
  def concat(*records)
@@ -38,49 +21,31 @@ module ActiveRecord
38
21
  super
39
22
  end
40
23
 
41
- def concat_records(records)
42
- ensure_not_nested
43
-
44
- records = super(records, true)
45
-
46
- if owner.new_record? && records
47
- records.flatten.each do |record|
48
- build_through_record(record)
49
- end
50
- end
51
-
52
- records
53
- end
54
-
55
24
  def insert_record(record, validate = true, raise = false)
56
25
  ensure_not_nested
57
26
 
58
- if record.new_record?
59
- if raise
60
- record.save!(:validate => validate)
61
- else
62
- return unless record.save(:validate => validate)
63
- end
27
+ if record.new_record? || record.has_changes_to_save?
28
+ return unless super
64
29
  end
65
30
 
66
31
  save_through_record(record)
67
- if has_cached_counter? && !through_reflection_updates_counter_cache?
68
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
69
- Automatic updating of counter caches on through associations has been
70
- deprecated, and will be removed in Rails 5. Instead, please set the
71
- appropriate `counter_cache` options on the `has_many` and `belongs_to`
72
- for your associations to #{through_reflection.name}.
73
- MSG
74
32
 
75
- update_counter_in_database(1)
76
- end
77
33
  record
78
34
  end
79
35
 
80
36
  private
37
+ def concat_records(records)
38
+ ensure_not_nested
39
+
40
+ records = super(records, true)
81
41
 
82
- def through_association
83
- @through_association ||= owner.association(through_reflection.name)
42
+ if owner.new_record? && records
43
+ records.flatten.each do |record|
44
+ build_through_record(record)
45
+ end
46
+ end
47
+
48
+ records
84
49
  end
85
50
 
86
51
  # The through record (built with build_record) is temporarily cached
@@ -89,40 +54,40 @@ module ActiveRecord
89
54
  # However, after insert_record has been called, the cache is cleared in
90
55
  # order to allow multiple instances of the same record in an association.
91
56
  def build_through_record(record)
92
- @through_records[record.object_id] ||= begin
57
+ @through_records[record] ||= begin
93
58
  ensure_mutable
94
59
 
95
- through_record = through_association.build(*options_for_through_record)
96
- through_record.send("#{source_reflection.name}=", record)
97
-
98
- if options[:source_type]
99
- through_record.send("#{source_reflection.foreign_type}=", options[:source_type])
100
- end
60
+ attributes = through_scope_attributes
61
+ attributes[source_reflection.name] = record
62
+ attributes[source_reflection.foreign_type] = options[:source_type] if options[:source_type]
101
63
 
102
- through_record
64
+ through_association.build(attributes)
103
65
  end
104
66
  end
105
67
 
106
- def options_for_through_record
107
- [through_scope_attributes]
108
- end
68
+ attr_reader :through_scope
109
69
 
110
70
  def through_scope_attributes
71
+ scope = through_scope || self.scope
111
72
  scope.where_values_hash(through_association.reflection.name.to_s).
112
73
  except!(through_association.reflection.foreign_key,
113
74
  through_association.reflection.klass.inheritance_column)
114
75
  end
115
76
 
116
77
  def save_through_record(record)
117
- build_through_record(record).save!
78
+ association = build_through_record(record)
79
+ if association.changed?
80
+ association.save!
81
+ end
118
82
  ensure
119
- @through_records.delete(record.object_id)
83
+ @through_records.delete(record)
120
84
  end
121
85
 
122
86
  def build_record(attributes)
123
87
  ensure_not_nested
124
88
 
125
- record = super(attributes)
89
+ @through_scope = scope
90
+ record = super
126
91
 
127
92
  inverse = source_reflection.inverse_of
128
93
  if inverse
@@ -134,6 +99,13 @@ module ActiveRecord
134
99
  end
135
100
 
136
101
  record
102
+ ensure
103
+ @through_scope = nil
104
+ end
105
+
106
+ def remove_records(existing_records, records, method)
107
+ super
108
+ delete_through_records(records)
137
109
  end
138
110
 
139
111
  def target_reflection_has_associated_record?
@@ -143,7 +115,7 @@ module ActiveRecord
143
115
  def update_through_counter?(method)
144
116
  case method
145
117
  when :destroy
146
- !inverse_updates_counter_cache?(through_reflection)
118
+ !through_reflection.inverse_updates_counter_cache?
147
119
  when :nullify
148
120
  false
149
121
  else
@@ -160,23 +132,15 @@ module ActiveRecord
160
132
 
161
133
  scope = through_association.scope
162
134
  scope.where! construct_join_attributes(*records)
135
+ scope = scope.where(through_scope_attributes)
163
136
 
164
137
  case method
165
138
  when :destroy
166
139
  if scope.klass.primary_key
167
- count = scope.destroy_all.length
140
+ count = scope.destroy_all.count(&:destroyed?)
168
141
  else
169
- scope.each do |record|
170
- record._run_destroy_callbacks
171
- end
172
-
173
- arel = scope.arel
174
-
175
- stmt = Arel::DeleteManager.new arel.engine
176
- stmt.from scope.klass.arel_table
177
- stmt.wheres = arel.constraints
178
-
179
- count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
142
+ scope.each(&:_run_destroy_callbacks)
143
+ count = scope.delete_all
180
144
  end
181
145
  when :nullify
182
146
  count = scope.update_all(source_reflection.foreign_key => nil)
@@ -196,6 +160,30 @@ module ActiveRecord
196
160
  else
197
161
  update_counter(-count)
198
162
  end
163
+
164
+ count
165
+ end
166
+
167
+ def difference(a, b)
168
+ distribution = distribution(b)
169
+
170
+ a.reject { |record| mark_occurrence(distribution, record) }
171
+ end
172
+
173
+ def intersection(a, b)
174
+ distribution = distribution(b)
175
+
176
+ a.select { |record| mark_occurrence(distribution, record) }
177
+ end
178
+
179
+ def mark_occurrence(distribution, record)
180
+ distribution[record] > 0 && distribution[record] -= 1
181
+ end
182
+
183
+ def distribution(array)
184
+ array.each_with_object(Hash.new(0)) do |record, distribution|
185
+ distribution[record] += 1
186
+ end
199
187
  end
200
188
 
201
189
  def through_records_for(record)
@@ -220,28 +208,19 @@ module ActiveRecord
220
208
  end
221
209
  end
222
210
 
223
- @through_records.delete(record.object_id)
211
+ @through_records.delete(record)
224
212
  end
225
213
  end
226
214
 
227
215
  def find_target
228
216
  return [] unless target_reflection_has_associated_record?
229
- get_records
217
+ super
230
218
  end
231
219
 
232
220
  # NOTE - not sure that we can actually cope with inverses here
233
221
  def invertible_for?(record)
234
222
  false
235
223
  end
236
-
237
- def has_cached_counter?(reflection = reflection())
238
- owner.attribute_present?(cached_counter_attribute_name(reflection))
239
- end
240
-
241
- def through_reflection_updates_counter_cache?
242
- counter_name = cached_counter_attribute_name
243
- inverse_updates_counter_named?(counter_name, through_reflection)
244
- end
245
224
  end
246
225
  end
247
226
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Belongs To Has One Association
3
4
  module Associations
5
+ # = Active Record Has One Association
4
6
  class HasOneAssociation < SingularAssociation #:nodoc:
5
7
  include ForeignAssociation
6
8
 
@@ -11,9 +13,9 @@ module ActiveRecord
11
13
 
12
14
  when :restrict_with_error
13
15
  if load_target
14
- record = klass.human_attribute_name(reflection.name).downcase
15
- owner.errors.add(:base, :"restrict_dependent_destroy.one", record: record)
16
- false
16
+ record = owner.class.human_attribute_name(reflection.name).downcase
17
+ owner.errors.add(:base, :'restrict_dependent_destroy.has_one', record: record)
18
+ throw(:abort)
17
19
  end
18
20
 
19
21
  else
@@ -21,49 +23,61 @@ module ActiveRecord
21
23
  end
22
24
  end
23
25
 
24
- def replace(record, save = true)
25
- raise_on_type_mismatch!(record) if record
26
- load_target
26
+ def delete(method = options[:dependent])
27
+ if load_target
28
+ case method
29
+ when :delete
30
+ target.delete
31
+ when :destroy
32
+ target.destroyed_by_association = reflection
33
+ target.destroy
34
+ throw(:abort) unless target.destroyed?
35
+ when :destroy_async
36
+ primary_key_column = target.class.primary_key.to_sym
37
+ id = target.public_send(primary_key_column)
38
+
39
+ enqueue_destroy_association(
40
+ owner_model_name: owner.class.to_s,
41
+ owner_id: owner.id,
42
+ association_class: reflection.klass.to_s,
43
+ association_ids: [id],
44
+ association_primary_key_column: primary_key_column,
45
+ ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
46
+ )
47
+ when :nullify
48
+ target.update_columns(nullified_owner_attributes) if target.persisted?
49
+ end
50
+ end
51
+ end
52
+
53
+ private
54
+ def replace(record, save = true)
55
+ raise_on_type_mismatch!(record) if record
27
56
 
28
- return self.target if !(target || record)
57
+ return target unless load_target || record
29
58
 
30
- assigning_another_record = target != record
31
- if assigning_another_record || record.changed?
32
- save &&= owner.persisted?
59
+ assigning_another_record = target != record
60
+ if assigning_another_record || record.has_changes_to_save?
61
+ save &&= owner.persisted?
33
62
 
34
- transaction_if(save) do
35
- remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
63
+ transaction_if(save) do
64
+ remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
36
65
 
37
- if record
38
- set_owner_attributes(record)
39
- set_inverse_instance(record)
66
+ if record
67
+ set_owner_attributes(record)
68
+ set_inverse_instance(record)
40
69
 
41
- if save && !record.save
42
- nullify_owner_attributes(record)
43
- set_owner_attributes(target) if target
44
- raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
70
+ if save && !record.save
71
+ nullify_owner_attributes(record)
72
+ set_owner_attributes(target) if target
73
+ raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
74
+ end
45
75
  end
46
76
  end
47
77
  end
48
- end
49
78
 
50
- self.target = record
51
- end
52
-
53
- def delete(method = options[:dependent])
54
- if load_target
55
- case method
56
- when :delete
57
- target.delete
58
- when :destroy
59
- target.destroy
60
- when :nullify
61
- target.update_columns(reflection.foreign_key => nil)
62
- end
79
+ self.target = record
63
80
  end
64
- end
65
-
66
- private
67
81
 
68
82
  # The reason that the save param for replace is false, if for create (not just build),
69
83
  # is because the setting of the foreign keys is actually handled by the scoping when
@@ -75,18 +89,22 @@ module ActiveRecord
75
89
 
76
90
  def remove_target!(method)
77
91
  case method
78
- when :delete
79
- target.delete
80
- when :destroy
92
+ when :delete
93
+ target.delete
94
+ when :destroy
95
+ target.destroyed_by_association = reflection
96
+ if target.persisted?
81
97
  target.destroy
82
- else
83
- nullify_owner_attributes(target)
98
+ end
99
+ else
100
+ nullify_owner_attributes(target)
101
+ remove_inverse_instance(target)
84
102
 
85
- if target.persisted? && owner.persisted? && !target.save
86
- set_owner_attributes(target)
87
- raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " +
88
- "The record failed to save after its foreign key was set to nil."
89
- end
103
+ if target.persisted? && owner.persisted? && !target.save
104
+ set_owner_attributes(target)
105
+ raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " \
106
+ "The record failed to save after its foreign key was set to nil."
107
+ end
90
108
  end
91
109
  end
92
110
 
@@ -101,6 +119,14 @@ module ActiveRecord
101
119
  yield
102
120
  end
103
121
  end
122
+
123
+ def _create_record(attributes, raise_error = false, &block)
124
+ unless owner.persisted?
125
+ raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
126
+ end
127
+
128
+ super
129
+ end
104
130
  end
105
131
  end
106
132
  end