activerecord 3.2.6 → 6.0.0

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 (371) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +611 -6417
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +44 -47
  5. data/examples/performance.rb +79 -71
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +268 -238
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +173 -81
  11. data/lib/active_record/associations/association_scope.rb +124 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -38
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +11 -9
  14. data/lib/active_record/associations/builder/association.rb +113 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +105 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +53 -56
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +98 -41
  18. data/lib/active_record/associations/builder/has_many.rb +11 -63
  19. data/lib/active_record/associations/builder/has_one.rb +47 -45
  20. data/lib/active_record/associations/builder/singular_association.rb +30 -18
  21. data/lib/active_record/associations/collection_association.rb +217 -295
  22. data/lib/active_record/associations/collection_proxy.rb +1074 -77
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +78 -50
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -61
  26. data/lib/active_record/associations/has_one_association.rb +75 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +45 -119
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +208 -164
  32. data/lib/active_record/associations/preloader/association.rb +93 -87
  33. data/lib/active_record/associations/preloader/through_association.rb +87 -38
  34. data/lib/active_record/associations/preloader.rb +134 -110
  35. data/lib/active_record/associations/singular_association.rb +19 -24
  36. data/lib/active_record/associations/through_association.rb +61 -27
  37. data/lib/active_record/associations.rb +1766 -1505
  38. data/lib/active_record/attribute_assignment.rb +57 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +58 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +187 -67
  42. data/lib/active_record/attribute_methods/primary_key.rb +100 -78
  43. data/lib/active_record/attribute_methods/query.rb +10 -8
  44. data/lib/active_record/attribute_methods/read.rb +29 -118
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -72
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -42
  47. data/lib/active_record/attribute_methods/write.rb +36 -44
  48. data/lib/active_record/attribute_methods.rb +306 -161
  49. data/lib/active_record/attributes.rb +279 -0
  50. data/lib/active_record/autosave_association.rb +324 -238
  51. data/lib/active_record/base.rb +114 -507
  52. data/lib/active_record/callbacks.rb +147 -83
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +962 -279
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +32 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +331 -209
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -23
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +201 -65
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +510 -289
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1182 -313
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +585 -120
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +610 -463
  68. data/lib/active_record/connection_adapters/column.rb +58 -233
  69. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +75 -207
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +695 -1052
  116. data/lib/active_record/connection_adapters/schema_cache.rb +115 -24
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +528 -26
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +267 -0
  128. data/lib/active_record/core.rb +599 -0
  129. data/lib/active_record/counter_cache.rb +177 -103
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +107 -64
  136. data/lib/active_record/enum.rb +274 -0
  137. data/lib/active_record/errors.rb +254 -61
  138. data/lib/active_record/explain.rb +35 -70
  139. data/lib/active_record/explain_registry.rb +32 -0
  140. data/lib/active_record/explain_subscriber.rb +18 -8
  141. data/lib/active_record/fixture_set/file.rb +82 -0
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +291 -475
  147. data/lib/active_record/gem_version.rb +17 -0
  148. data/lib/active_record/inheritance.rb +219 -100
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +175 -17
  151. data/lib/active_record/internal_metadata.rb +53 -0
  152. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  153. data/lib/active_record/locale/en.yml +9 -1
  154. data/lib/active_record/locking/optimistic.rb +106 -92
  155. data/lib/active_record/locking/pessimistic.rb +23 -11
  156. data/lib/active_record/log_subscriber.rb +80 -30
  157. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  158. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  159. data/lib/active_record/middleware/database_selector.rb +75 -0
  160. data/lib/active_record/migration/command_recorder.rb +235 -56
  161. data/lib/active_record/migration/compatibility.rb +244 -0
  162. data/lib/active_record/migration/join_table.rb +17 -0
  163. data/lib/active_record/migration.rb +917 -301
  164. data/lib/active_record/model_schema.rb +351 -175
  165. data/lib/active_record/nested_attributes.rb +366 -235
  166. data/lib/active_record/no_touching.rb +65 -0
  167. data/lib/active_record/null_relation.rb +68 -0
  168. data/lib/active_record/persistence.rb +761 -166
  169. data/lib/active_record/query_cache.rb +22 -44
  170. data/lib/active_record/querying.rb +55 -31
  171. data/lib/active_record/railtie.rb +185 -47
  172. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  173. data/lib/active_record/railties/console_sandbox.rb +5 -4
  174. data/lib/active_record/railties/controller_runtime.rb +35 -33
  175. data/lib/active_record/railties/databases.rake +366 -463
  176. data/lib/active_record/readonly_attributes.rb +4 -6
  177. data/lib/active_record/reflection.rb +736 -228
  178. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  179. data/lib/active_record/relation/batches.rb +252 -52
  180. data/lib/active_record/relation/calculations.rb +340 -270
  181. data/lib/active_record/relation/delegation.rb +117 -36
  182. data/lib/active_record/relation/finder_methods.rb +439 -286
  183. data/lib/active_record/relation/from_clause.rb +26 -0
  184. data/lib/active_record/relation/merger.rb +184 -0
  185. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  186. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  187. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  188. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  189. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  190. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  191. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder.rb +131 -39
  193. data/lib/active_record/relation/query_attribute.rb +50 -0
  194. data/lib/active_record/relation/query_methods.rb +1163 -221
  195. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  196. data/lib/active_record/relation/spawn_methods.rb +49 -120
  197. data/lib/active_record/relation/where_clause.rb +190 -0
  198. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  199. data/lib/active_record/relation.rb +671 -349
  200. data/lib/active_record/result.rb +149 -15
  201. data/lib/active_record/runtime_registry.rb +24 -0
  202. data/lib/active_record/sanitization.rb +153 -133
  203. data/lib/active_record/schema.rb +22 -19
  204. data/lib/active_record/schema_dumper.rb +178 -112
  205. data/lib/active_record/schema_migration.rb +60 -0
  206. data/lib/active_record/scoping/default.rb +107 -98
  207. data/lib/active_record/scoping/named.rb +130 -115
  208. data/lib/active_record/scoping.rb +77 -123
  209. data/lib/active_record/secure_token.rb +40 -0
  210. data/lib/active_record/serialization.rb +10 -6
  211. data/lib/active_record/statement_cache.rb +148 -0
  212. data/lib/active_record/store.rb +256 -16
  213. data/lib/active_record/suppressor.rb +61 -0
  214. data/lib/active_record/table_metadata.rb +75 -0
  215. data/lib/active_record/tasks/database_tasks.rb +506 -0
  216. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  217. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  218. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  219. data/lib/active_record/test_databases.rb +23 -0
  220. data/lib/active_record/test_fixtures.rb +224 -0
  221. data/lib/active_record/timestamp.rb +93 -39
  222. data/lib/active_record/touch_later.rb +66 -0
  223. data/lib/active_record/transactions.rb +260 -129
  224. data/lib/active_record/translation.rb +3 -1
  225. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  226. data/lib/active_record/type/date.rb +9 -0
  227. data/lib/active_record/type/date_time.rb +9 -0
  228. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  229. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  230. data/lib/active_record/type/internal/timezone.rb +17 -0
  231. data/lib/active_record/type/json.rb +30 -0
  232. data/lib/active_record/type/serialized.rb +71 -0
  233. data/lib/active_record/type/text.rb +11 -0
  234. data/lib/active_record/type/time.rb +21 -0
  235. data/lib/active_record/type/type_map.rb +62 -0
  236. data/lib/active_record/type/unsigned_integer.rb +17 -0
  237. data/lib/active_record/type.rb +78 -0
  238. data/lib/active_record/type_caster/connection.rb +34 -0
  239. data/lib/active_record/type_caster/map.rb +20 -0
  240. data/lib/active_record/type_caster.rb +9 -0
  241. data/lib/active_record/validations/absence.rb +25 -0
  242. data/lib/active_record/validations/associated.rb +35 -18
  243. data/lib/active_record/validations/length.rb +26 -0
  244. data/lib/active_record/validations/presence.rb +68 -0
  245. data/lib/active_record/validations/uniqueness.rb +123 -77
  246. data/lib/active_record/validations.rb +54 -43
  247. data/lib/active_record/version.rb +7 -7
  248. data/lib/active_record.rb +97 -49
  249. data/lib/arel/alias_predication.rb +9 -0
  250. data/lib/arel/attributes/attribute.rb +37 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/collectors/bind.rb +24 -0
  253. data/lib/arel/collectors/composite.rb +31 -0
  254. data/lib/arel/collectors/plain_string.rb +20 -0
  255. data/lib/arel/collectors/sql_string.rb +20 -0
  256. data/lib/arel/collectors/substitute_binds.rb +28 -0
  257. data/lib/arel/crud.rb +42 -0
  258. data/lib/arel/delete_manager.rb +18 -0
  259. data/lib/arel/errors.rb +9 -0
  260. data/lib/arel/expressions.rb +29 -0
  261. data/lib/arel/factory_methods.rb +49 -0
  262. data/lib/arel/insert_manager.rb +49 -0
  263. data/lib/arel/math.rb +45 -0
  264. data/lib/arel/nodes/and.rb +32 -0
  265. data/lib/arel/nodes/ascending.rb +23 -0
  266. data/lib/arel/nodes/binary.rb +52 -0
  267. data/lib/arel/nodes/bind_param.rb +36 -0
  268. data/lib/arel/nodes/case.rb +55 -0
  269. data/lib/arel/nodes/casted.rb +50 -0
  270. data/lib/arel/nodes/comment.rb +29 -0
  271. data/lib/arel/nodes/count.rb +12 -0
  272. data/lib/arel/nodes/delete_statement.rb +45 -0
  273. data/lib/arel/nodes/descending.rb +23 -0
  274. data/lib/arel/nodes/equality.rb +18 -0
  275. data/lib/arel/nodes/extract.rb +24 -0
  276. data/lib/arel/nodes/false.rb +16 -0
  277. data/lib/arel/nodes/full_outer_join.rb +8 -0
  278. data/lib/arel/nodes/function.rb +44 -0
  279. data/lib/arel/nodes/grouping.rb +8 -0
  280. data/lib/arel/nodes/in.rb +8 -0
  281. data/lib/arel/nodes/infix_operation.rb +80 -0
  282. data/lib/arel/nodes/inner_join.rb +8 -0
  283. data/lib/arel/nodes/insert_statement.rb +37 -0
  284. data/lib/arel/nodes/join_source.rb +20 -0
  285. data/lib/arel/nodes/matches.rb +18 -0
  286. data/lib/arel/nodes/named_function.rb +23 -0
  287. data/lib/arel/nodes/node.rb +50 -0
  288. data/lib/arel/nodes/node_expression.rb +13 -0
  289. data/lib/arel/nodes/outer_join.rb +8 -0
  290. data/lib/arel/nodes/over.rb +15 -0
  291. data/lib/arel/nodes/regexp.rb +16 -0
  292. data/lib/arel/nodes/right_outer_join.rb +8 -0
  293. data/lib/arel/nodes/select_core.rb +67 -0
  294. data/lib/arel/nodes/select_statement.rb +41 -0
  295. data/lib/arel/nodes/sql_literal.rb +16 -0
  296. data/lib/arel/nodes/string_join.rb +11 -0
  297. data/lib/arel/nodes/table_alias.rb +27 -0
  298. data/lib/arel/nodes/terminal.rb +16 -0
  299. data/lib/arel/nodes/true.rb +16 -0
  300. data/lib/arel/nodes/unary.rb +45 -0
  301. data/lib/arel/nodes/unary_operation.rb +20 -0
  302. data/lib/arel/nodes/unqualified_column.rb +22 -0
  303. data/lib/arel/nodes/update_statement.rb +41 -0
  304. data/lib/arel/nodes/values_list.rb +9 -0
  305. data/lib/arel/nodes/window.rb +126 -0
  306. data/lib/arel/nodes/with.rb +11 -0
  307. data/lib/arel/nodes.rb +68 -0
  308. data/lib/arel/order_predications.rb +13 -0
  309. data/lib/arel/predications.rb +257 -0
  310. data/lib/arel/select_manager.rb +271 -0
  311. data/lib/arel/table.rb +110 -0
  312. data/lib/arel/tree_manager.rb +72 -0
  313. data/lib/arel/update_manager.rb +34 -0
  314. data/lib/arel/visitors/depth_first.rb +204 -0
  315. data/lib/arel/visitors/dot.rb +297 -0
  316. data/lib/arel/visitors/ibm_db.rb +34 -0
  317. data/lib/arel/visitors/informix.rb +62 -0
  318. data/lib/arel/visitors/mssql.rb +157 -0
  319. data/lib/arel/visitors/mysql.rb +83 -0
  320. data/lib/arel/visitors/oracle.rb +159 -0
  321. data/lib/arel/visitors/oracle12.rb +66 -0
  322. data/lib/arel/visitors/postgresql.rb +110 -0
  323. data/lib/arel/visitors/sqlite.rb +39 -0
  324. data/lib/arel/visitors/to_sql.rb +889 -0
  325. data/lib/arel/visitors/visitor.rb +46 -0
  326. data/lib/arel/visitors/where_sql.rb +23 -0
  327. data/lib/arel/visitors.rb +20 -0
  328. data/lib/arel/window_predications.rb +9 -0
  329. data/lib/arel.rb +51 -0
  330. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  331. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +59 -9
  333. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  334. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  335. data/lib/rails/generators/active_record/migration.rb +41 -8
  336. data/lib/rails/generators/active_record/model/model_generator.rb +24 -22
  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} +1 -1
  339. data/lib/rails/generators/active_record.rb +10 -16
  340. metadata +285 -149
  341. data/examples/associations.png +0 -0
  342. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  343. data/lib/active_record/associations/join_helper.rb +0 -55
  344. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  345. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  346. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  347. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  348. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  349. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  350. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  351. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  352. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  353. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -188
  354. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -426
  355. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -579
  356. data/lib/active_record/dynamic_finder_match.rb +0 -68
  357. data/lib/active_record/dynamic_scope_match.rb +0 -23
  358. data/lib/active_record/fixtures/file.rb +0 -65
  359. data/lib/active_record/identity_map.rb +0 -162
  360. data/lib/active_record/observer.rb +0 -121
  361. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  362. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  363. data/lib/active_record/session_store.rb +0 -358
  364. data/lib/active_record/test_case.rb +0 -73
  365. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  366. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  367. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  368. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  369. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  370. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  371. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,85 +1,130 @@
1
- require 'active_support/core_ext/object/inclusion'
1
+ # frozen_string_literal: true
2
2
 
3
- module ActiveRecord::Associations::Builder
3
+ module ActiveRecord::Associations::Builder # :nodoc:
4
4
  class BelongsTo < SingularAssociation #:nodoc:
5
- self.macro = :belongs_to
5
+ def self.macro
6
+ :belongs_to
7
+ end
6
8
 
7
- self.valid_options += [:foreign_type, :polymorphic, :touch]
9
+ def self.valid_options(options)
10
+ super + [:polymorphic, :touch, :counter_cache, :optional, :default]
11
+ end
8
12
 
9
- def constructable?
10
- !options[:polymorphic]
13
+ def self.valid_dependent_options
14
+ [:destroy, :delete]
11
15
  end
12
16
 
13
- def build
14
- reflection = super
15
- add_counter_cache_callbacks(reflection) if options[:counter_cache]
16
- add_touch_callbacks(reflection) if options[:touch]
17
- configure_dependency
18
- reflection
17
+ def self.define_callbacks(model, reflection)
18
+ super
19
+ add_counter_cache_callbacks(model, reflection) if reflection.options[:counter_cache]
20
+ add_touch_callbacks(model, reflection) if reflection.options[:touch]
21
+ add_default_callbacks(model, reflection) if reflection.options[:default]
19
22
  end
20
23
 
21
- private
24
+ def self.add_counter_cache_callbacks(model, reflection)
25
+ cache_column = reflection.counter_cache_column
22
26
 
23
- def add_counter_cache_callbacks(reflection)
24
- cache_column = reflection.counter_cache_column
25
- name = self.name
27
+ model.after_update lambda { |record|
28
+ association = association(reflection.name)
26
29
 
27
- method_name = "belongs_to_counter_cache_after_create_for_#{name}"
28
- mixin.redefine_method(method_name) do
29
- record = send(name)
30
- record.class.increment_counter(cache_column, record.id) unless record.nil?
30
+ if association.target_changed?
31
+ association.increment_counters
32
+ association.decrement_counters_before_last_save
31
33
  end
32
- model.after_create(method_name)
34
+ }
35
+
36
+ klass = reflection.class_name.safe_constantize
37
+ klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly)
38
+ end
33
39
 
34
- method_name = "belongs_to_counter_cache_before_destroy_for_#{name}"
35
- mixin.redefine_method(method_name) do
36
- record = send(name)
37
- record.class.decrement_counter(cache_column, record.id) unless record.nil?
40
+ def self.touch_record(o, changes, foreign_key, name, touch, touch_method) # :nodoc:
41
+ old_foreign_id = changes[foreign_key] && changes[foreign_key].first
42
+
43
+ if old_foreign_id
44
+ association = o.association(name)
45
+ reflection = association.reflection
46
+ if reflection.polymorphic?
47
+ foreign_type = reflection.foreign_type
48
+ klass = changes[foreign_type] && changes[foreign_type].first || o.public_send(foreign_type)
49
+ klass = klass.constantize
50
+ else
51
+ klass = association.klass
38
52
  end
39
- model.before_destroy(method_name)
53
+ primary_key = reflection.association_primary_key(klass)
54
+ old_record = klass.find_by(primary_key => old_foreign_id)
40
55
 
41
- model.send(:module_eval,
42
- "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)", __FILE__, __LINE__
43
- )
56
+ if old_record
57
+ if touch != true
58
+ old_record.send(touch_method, touch)
59
+ else
60
+ old_record.send(touch_method)
61
+ end
62
+ end
44
63
  end
45
64
 
46
- def add_touch_callbacks(reflection)
47
- name = self.name
48
- method_name = "belongs_to_touch_after_save_or_destroy_for_#{name}"
49
- touch = options[:touch]
65
+ record = o.send name
66
+ if record && record.persisted?
67
+ if touch != true
68
+ record.send(touch_method, touch)
69
+ else
70
+ record.send(touch_method)
71
+ end
72
+ end
73
+ end
50
74
 
51
- mixin.redefine_method(method_name) do
52
- record = send(name)
75
+ def self.add_touch_callbacks(model, reflection)
76
+ foreign_key = reflection.foreign_key
77
+ name = reflection.name
78
+ touch = reflection.options[:touch]
53
79
 
54
- unless record.nil?
55
- if touch == true
56
- record.touch
57
- else
58
- record.touch(touch)
59
- end
60
- end
61
- end
80
+ callback = lambda { |changes_method| lambda { |record|
81
+ BelongsTo.touch_record(record, record.send(changes_method), foreign_key, name, touch, belongs_to_touch_method)
82
+ }}
62
83
 
63
- model.after_save(method_name)
64
- model.after_touch(method_name)
65
- model.after_destroy(method_name)
84
+ if reflection.counter_cache_column
85
+ touch_callback = callback.(:saved_changes)
86
+ update_callback = lambda { |record|
87
+ instance_exec(record, &touch_callback) unless association(reflection.name).target_changed?
88
+ }
89
+ model.after_update update_callback, if: :saved_changes?
90
+ else
91
+ model.after_create callback.(:saved_changes), if: :saved_changes?
92
+ model.after_update callback.(:saved_changes), if: :saved_changes?
93
+ model.after_destroy callback.(:changes_to_save)
66
94
  end
67
95
 
68
- def configure_dependency
69
- if options[:dependent]
70
- unless options[:dependent].in?([:destroy, :delete])
71
- raise ArgumentError, "The :dependent option expects either :destroy or :delete (#{options[:dependent].inspect})"
72
- end
96
+ model.after_touch callback.(:changes_to_save)
97
+ end
73
98
 
74
- method_name = "belongs_to_dependent_#{options[:dependent]}_for_#{name}"
75
- model.send(:class_eval, <<-eoruby, __FILE__, __LINE__ + 1)
76
- def #{method_name}
77
- association = #{name}
78
- association.#{options[:dependent]} if association
79
- end
80
- eoruby
81
- model.after_destroy method_name
82
- end
99
+ def self.add_default_callbacks(model, reflection)
100
+ model.before_validation lambda { |o|
101
+ o.association(reflection.name).default(&reflection.options[:default])
102
+ }
103
+ end
104
+
105
+ def self.add_destroy_callbacks(model, reflection)
106
+ model.after_destroy lambda { |o| o.association(reflection.name).handle_dependency }
107
+ end
108
+
109
+ def self.define_validations(model, reflection)
110
+ if reflection.options.key?(:required)
111
+ reflection.options[:optional] = !reflection.options.delete(:required)
83
112
  end
113
+
114
+ if reflection.options[:optional].nil?
115
+ required = model.belongs_to_required_by_default
116
+ else
117
+ required = !reflection.options[:optional]
118
+ end
119
+
120
+ super
121
+
122
+ if required
123
+ model.validates_presence_of reflection.name, message: :required
124
+ end
125
+ end
126
+
127
+ private_class_method :macro, :valid_options, :valid_dependent_options, :define_callbacks, :define_validations,
128
+ :add_counter_cache_callbacks, :add_touch_callbacks, :add_default_callbacks, :add_destroy_callbacks
84
129
  end
85
130
  end
@@ -1,75 +1,72 @@
1
- module ActiveRecord::Associations::Builder
2
- class CollectionAssociation < Association #:nodoc:
3
- CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
4
-
5
- self.valid_options += [
6
- :table_name, :order, :group, :having, :limit, :offset, :uniq, :finder_sql,
7
- :counter_sql, :before_add, :after_add, :before_remove, :after_remove
8
- ]
1
+ # frozen_string_literal: true
9
2
 
10
- attr_reader :block_extension
3
+ require "active_record/associations"
11
4
 
12
- def self.build(model, name, options, &extension)
13
- new(model, name, options, &extension).build
14
- end
5
+ module ActiveRecord::Associations::Builder # :nodoc:
6
+ class CollectionAssociation < Association #:nodoc:
7
+ CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
15
8
 
16
- def initialize(model, name, options, &extension)
17
- super(model, name, options)
18
- @block_extension = extension
9
+ def self.valid_options(options)
10
+ super + [:table_name, :before_add,
11
+ :after_add, :before_remove, :after_remove, :extend]
19
12
  end
20
13
 
21
- def build
22
- wrap_block_extension
23
- reflection = super
24
- CALLBACKS.each { |callback_name| define_callback(callback_name) }
25
- reflection
14
+ def self.define_callbacks(model, reflection)
15
+ super
16
+ name = reflection.name
17
+ options = reflection.options
18
+ CALLBACKS.each { |callback_name|
19
+ define_callback(model, callback_name, name, options)
20
+ }
26
21
  end
27
22
 
28
- def writable?
29
- true
23
+ def self.define_extensions(model, name, &block)
24
+ if block_given?
25
+ extension_module_name = "#{name.to_s.camelize}AssociationExtension"
26
+ extension = Module.new(&block)
27
+ model.const_set(extension_module_name, extension)
28
+ end
30
29
  end
31
30
 
32
- private
33
-
34
- def wrap_block_extension
35
- options[:extend] = Array.wrap(options[:extend])
36
-
37
- if block_extension
38
- silence_warnings do
39
- model.parent.const_set(extension_module_name, Module.new(&block_extension))
40
- end
41
- options[:extend].push("#{model.parent}::#{extension_module_name}".constantize)
31
+ def self.define_callback(model, callback_name, name, options)
32
+ full_callback_name = "#{callback_name}_for_#{name}"
33
+
34
+ # TODO : why do i need method_defined? I think its because of the inheritance chain
35
+ model.class_attribute full_callback_name unless model.method_defined?(full_callback_name)
36
+ callbacks = Array(options[callback_name.to_sym]).map do |callback|
37
+ case callback
38
+ when Symbol
39
+ ->(method, owner, record) { owner.send(callback, record) }
40
+ when Proc
41
+ ->(method, owner, record) { callback.call(owner, record) }
42
+ else
43
+ ->(method, owner, record) { callback.send(method, owner, record) }
42
44
  end
43
45
  end
46
+ model.send "#{full_callback_name}=", callbacks
47
+ end
44
48
 
45
- def extension_module_name
46
- @extension_module_name ||= "#{model.to_s.demodulize}#{name.to_s.camelize}AssociationExtension"
47
- end
48
-
49
- def define_callback(callback_name)
50
- full_callback_name = "#{callback_name}_for_#{name}"
51
-
52
- # TODO : why do i need method_defined? I think its because of the inheritance chain
53
- model.class_attribute full_callback_name.to_sym unless model.method_defined?(full_callback_name)
54
- model.send("#{full_callback_name}=", Array.wrap(options[callback_name.to_sym]))
55
- end
56
-
57
- def define_readers
58
- super
49
+ # Defines the setter and getter methods for the collection_singular_ids.
50
+ def self.define_readers(mixin, name)
51
+ super
59
52
 
60
- name = self.name
61
- mixin.redefine_method("#{name.to_s.singularize}_ids") do
62
- association(name).ids_reader
53
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
54
+ def #{name.to_s.singularize}_ids
55
+ association(:#{name}).ids_reader
63
56
  end
64
- end
57
+ CODE
58
+ end
65
59
 
66
- def define_writers
67
- super
60
+ def self.define_writers(mixin, name)
61
+ super
68
62
 
69
- name = self.name
70
- mixin.redefine_method("#{name.to_s.singularize}_ids=") do |ids|
71
- association(name).ids_writer(ids)
63
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
64
+ def #{name.to_s.singularize}_ids=(ids)
65
+ association(:#{name}).ids_writer(ids)
72
66
  end
73
- end
67
+ CODE
68
+ end
69
+
70
+ private_class_method :valid_options, :define_callback, :define_extensions, :define_readers, :define_writers
74
71
  end
75
72
  end
@@ -1,57 +1,114 @@
1
- module ActiveRecord::Associations::Builder
2
- class HasAndBelongsToMany < CollectionAssociation #:nodoc:
3
- self.macro = :has_and_belongs_to_many
1
+ # frozen_string_literal: true
4
2
 
5
- self.valid_options += [:join_table, :association_foreign_key, :delete_sql, :insert_sql]
3
+ module ActiveRecord::Associations::Builder # :nodoc:
4
+ class HasAndBelongsToMany # :nodoc:
5
+ attr_reader :lhs_model, :association_name, :options
6
6
 
7
- def build
8
- reflection = super
9
- check_validity(reflection)
10
- define_destroy_hook
11
- reflection
7
+ def initialize(association_name, lhs_model, options)
8
+ @association_name = association_name
9
+ @lhs_model = lhs_model
10
+ @options = options
12
11
  end
13
12
 
14
- private
13
+ def through_model
14
+ join_model = Class.new(ActiveRecord::Base) {
15
+ class << self
16
+ attr_accessor :left_model
17
+ attr_accessor :name
18
+ attr_accessor :table_name_resolver
19
+ attr_accessor :left_reflection
20
+ attr_accessor :right_reflection
21
+ end
15
22
 
16
- def define_destroy_hook
17
- name = self.name
18
- model.send(:include, Module.new {
19
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
20
- def destroy_associations
21
- association(#{name.to_sym.inspect}).delete_all_on_destroy
22
- super
23
- end
24
- RUBY
25
- })
26
- end
23
+ def self.table_name
24
+ # Table name needs to be resolved lazily
25
+ # because RHS class might not have been loaded
26
+ @table_name ||= table_name_resolver.call
27
+ end
28
+
29
+ def self.compute_type(class_name)
30
+ left_model.compute_type class_name
31
+ end
32
+
33
+ def self.add_left_association(name, options)
34
+ belongs_to name, required: false, **options
35
+ self.left_reflection = _reflect_on_association(name)
36
+ end
37
+
38
+ def self.add_right_association(name, options)
39
+ rhs_name = name.to_s.singularize.to_sym
40
+ belongs_to rhs_name, required: false, **options
41
+ self.right_reflection = _reflect_on_association(rhs_name)
42
+ end
27
43
 
28
- # TODO: These checks should probably be moved into the Reflection, and we should not be
29
- # redefining the options[:join_table] value - instead we should define a
30
- # reflection.join_table method.
31
- def check_validity(reflection)
32
- if reflection.association_foreign_key == reflection.foreign_key
33
- raise ActiveRecord::HasAndBelongsToManyAssociationForeignKeyNeeded.new(reflection)
44
+ def self.retrieve_connection
45
+ left_model.retrieve_connection
34
46
  end
35
47
 
36
- reflection.options[:join_table] ||= join_table_name(
37
- model.send(:undecorated_table_name, model.to_s),
38
- model.send(:undecorated_table_name, reflection.class_name)
39
- )
48
+ private
49
+
50
+ def self.suppress_composite_primary_key(pk)
51
+ pk unless pk.is_a?(Array)
52
+ end
53
+ }
54
+
55
+ join_model.name = "HABTM_#{association_name.to_s.camelize}"
56
+ join_model.table_name_resolver = -> { table_name }
57
+ join_model.left_model = lhs_model
58
+
59
+ join_model.add_left_association :left_side, anonymous_class: lhs_model
60
+ join_model.add_right_association association_name, belongs_to_options(options)
61
+ join_model
62
+ end
63
+
64
+ def middle_reflection(join_model)
65
+ middle_name = [lhs_model.name.downcase.pluralize,
66
+ association_name.to_s].sort.join("_").gsub("::", "_").to_sym
67
+ middle_options = middle_options join_model
68
+
69
+ HasMany.create_reflection(lhs_model,
70
+ middle_name,
71
+ nil,
72
+ middle_options)
73
+ end
74
+
75
+ private
76
+
77
+ def middle_options(join_model)
78
+ middle_options = {}
79
+ middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
80
+ middle_options[:source] = join_model.left_reflection.name
81
+ if options.key? :foreign_key
82
+ middle_options[:foreign_key] = options[:foreign_key]
83
+ end
84
+ middle_options
40
85
  end
41
86
 
42
- # Generates a join table name from two provided table names.
43
- # The names in the join table names end up in lexicographic order.
44
- #
45
- # join_table_name("members", "clubs") # => "clubs_members"
46
- # join_table_name("members", "special_clubs") # => "members_special_clubs"
47
- def join_table_name(first_table_name, second_table_name)
48
- if first_table_name < second_table_name
49
- join_table = "#{first_table_name}_#{second_table_name}"
87
+ def table_name
88
+ if options[:join_table]
89
+ options[:join_table].to_s
50
90
  else
51
- join_table = "#{second_table_name}_#{first_table_name}"
91
+ class_name = options.fetch(:class_name) {
92
+ association_name.to_s.camelize.singularize
93
+ }
94
+ klass = lhs_model.send(:compute_type, class_name.to_s)
95
+ [lhs_model.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
96
+ end
97
+ end
98
+
99
+ def belongs_to_options(options)
100
+ rhs_options = {}
101
+
102
+ if options.key? :class_name
103
+ rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
104
+ rhs_options[:class_name] = options[:class_name]
105
+ end
106
+
107
+ if options.key? :association_foreign_key
108
+ rhs_options[:foreign_key] = options[:association_foreign_key]
52
109
  end
53
110
 
54
- model.table_name_prefix + join_table + model.table_name_suffix
111
+ rhs_options
55
112
  end
56
113
  end
57
114
  end
@@ -1,71 +1,19 @@
1
- require 'active_support/core_ext/object/inclusion'
1
+ # frozen_string_literal: true
2
2
 
3
- module ActiveRecord::Associations::Builder
3
+ module ActiveRecord::Associations::Builder # :nodoc:
4
4
  class HasMany < CollectionAssociation #:nodoc:
5
- self.macro = :has_many
6
-
7
- self.valid_options += [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of]
8
-
9
- def build
10
- reflection = super
11
- configure_dependency
12
- reflection
5
+ def self.macro
6
+ :has_many
13
7
  end
14
8
 
15
- private
16
-
17
- def configure_dependency
18
- if options[:dependent]
19
- unless options[:dependent].in?([:destroy, :delete_all, :nullify, :restrict])
20
- raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, " \
21
- ":nullify or :restrict (#{options[:dependent].inspect})"
22
- end
23
-
24
- send("define_#{options[:dependent]}_dependency_method")
25
- model.before_destroy dependency_method_name
26
- end
27
- end
28
-
29
- def define_destroy_dependency_method
30
- name = self.name
31
- mixin.redefine_method(dependency_method_name) do
32
- send(name).each do |o|
33
- # No point in executing the counter update since we're going to destroy the parent anyway
34
- counter_method = ('belongs_to_counter_cache_before_destroy_for_' + self.class.name.downcase).to_sym
35
- if o.respond_to?(counter_method)
36
- class << o
37
- self
38
- end.send(:define_method, counter_method, Proc.new {})
39
- end
40
- end
41
-
42
- send(name).delete_all
43
- end
44
- end
45
-
46
- def define_delete_all_dependency_method
47
- name = self.name
48
- mixin.redefine_method(dependency_method_name) do
49
- association(name).delete_all_on_destroy
50
- end
51
- end
52
-
53
- def define_nullify_dependency_method
54
- name = self.name
55
- mixin.redefine_method(dependency_method_name) do
56
- send(name).delete_all
57
- end
58
- end
9
+ def self.valid_options(options)
10
+ super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache, :join_table, :foreign_type, :index_errors]
11
+ end
59
12
 
60
- def define_restrict_dependency_method
61
- name = self.name
62
- mixin.redefine_method(dependency_method_name) do
63
- raise ActiveRecord::DeleteRestrictionError.new(name) unless send(name).empty?
64
- end
65
- end
13
+ def self.valid_dependent_options
14
+ [:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception]
15
+ end
66
16
 
67
- def dependency_method_name
68
- "has_many_dependent_for_#{name}"
69
- end
17
+ private_class_method :macro, :valid_options, :valid_dependent_options
70
18
  end
71
19
  end
@@ -1,62 +1,64 @@
1
- require 'active_support/core_ext/object/inclusion'
1
+ # frozen_string_literal: true
2
2
 
3
- module ActiveRecord::Associations::Builder
3
+ module ActiveRecord::Associations::Builder # :nodoc:
4
4
  class HasOne < SingularAssociation #:nodoc:
5
- self.macro = :has_one
6
-
7
- self.valid_options += [:order, :as]
5
+ def self.macro
6
+ :has_one
7
+ end
8
8
 
9
- class_attribute :through_options
10
- self.through_options = [:through, :source, :source_type]
9
+ def self.valid_options(options)
10
+ valid = super + [:as, :touch]
11
+ valid += [:through, :source, :source_type] if options[:through]
12
+ valid
13
+ end
11
14
 
12
- def constructable?
13
- !options[:through]
15
+ def self.valid_dependent_options
16
+ [:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
14
17
  end
15
18
 
16
- def build
17
- reflection = super
18
- configure_dependency unless options[:through]
19
- reflection
19
+ def self.define_callbacks(model, reflection)
20
+ super
21
+ add_touch_callbacks(model, reflection) if reflection.options[:touch]
20
22
  end
21
23
 
22
- private
24
+ def self.add_destroy_callbacks(model, reflection)
25
+ super unless reflection.options[:through]
26
+ end
23
27
 
24
- def validate_options
25
- valid_options = self.class.valid_options
26
- valid_options += self.class.through_options if options[:through]
27
- options.assert_valid_keys(valid_options)
28
+ def self.define_validations(model, reflection)
29
+ super
30
+ if reflection.options[:required]
31
+ model.validates_presence_of reflection.name, message: :required
28
32
  end
33
+ end
29
34
 
30
- def configure_dependency
31
- if options[:dependent]
32
- unless options[:dependent].in?([:destroy, :delete, :nullify, :restrict])
33
- raise ArgumentError, "The :dependent option expects either :destroy, :delete, " \
34
- ":nullify or :restrict (#{options[:dependent].inspect})"
35
- end
35
+ def self.touch_record(o, name, touch)
36
+ record = o.send name
36
37
 
37
- send("define_#{options[:dependent]}_dependency_method")
38
- model.before_destroy dependency_method_name
39
- end
40
- end
38
+ return unless record && record.persisted?
41
39
 
42
- def dependency_method_name
43
- "has_one_dependent_#{options[:dependent]}_for_#{name}"
40
+ if touch != true
41
+ record.touch(touch)
42
+ else
43
+ record.touch
44
44
  end
45
+ end
45
46
 
46
- def define_destroy_dependency_method
47
- name = self.name
48
- mixin.redefine_method(dependency_method_name) do
49
- association(name).delete
50
- end
51
- end
52
- alias :define_delete_dependency_method :define_destroy_dependency_method
53
- alias :define_nullify_dependency_method :define_destroy_dependency_method
54
-
55
- def define_restrict_dependency_method
56
- name = self.name
57
- mixin.redefine_method(dependency_method_name) do
58
- raise ActiveRecord::DeleteRestrictionError.new(name) unless send(name).nil?
59
- end
60
- end
47
+ def self.add_touch_callbacks(model, reflection)
48
+ name = reflection.name
49
+ touch = reflection.options[:touch]
50
+
51
+ callback = lambda { |record|
52
+ HasOne.touch_record(record, name, touch)
53
+ }
54
+
55
+ model.after_create callback, if: :saved_changes?
56
+ model.after_update callback, if: :saved_changes?
57
+ model.after_destroy callback
58
+ model.after_touch callback
59
+ end
60
+
61
+ private_class_method :macro, :valid_options, :valid_dependent_options, :add_destroy_callbacks,
62
+ :define_callbacks, :define_validations, :add_touch_callbacks
61
63
  end
62
64
  end