activerecord 4.2.0 → 6.1.7.1

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