activerecord 5.0.7.2 → 6.1.1

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

Potentially problematic release.


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

Files changed (363) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +829 -2015
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +11 -9
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -29
  8. data/lib/active_record/aggregations.rb +249 -247
  9. data/lib/active_record/association_relation.rb +30 -18
  10. data/lib/active_record/associations.rb +1714 -1596
  11. data/lib/active_record/associations/alias_tracker.rb +36 -42
  12. data/lib/active_record/associations/association.rb +143 -68
  13. data/lib/active_record/associations/association_scope.rb +98 -94
  14. data/lib/active_record/associations/belongs_to_association.rb +76 -46
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -28
  17. data/lib/active_record/associations/builder/belongs_to.rb +52 -60
  18. data/lib/active_record/associations/builder/collection_association.rb +12 -22
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
  20. data/lib/active_record/associations/builder/has_many.rb +10 -2
  21. data/lib/active_record/associations/builder/has_one.rb +35 -2
  22. data/lib/active_record/associations/builder/singular_association.rb +5 -1
  23. data/lib/active_record/associations/collection_association.rb +104 -259
  24. data/lib/active_record/associations/collection_proxy.rb +169 -125
  25. data/lib/active_record/associations/foreign_association.rb +22 -0
  26. data/lib/active_record/associations/has_many_association.rb +46 -31
  27. data/lib/active_record/associations/has_many_through_association.rb +66 -46
  28. data/lib/active_record/associations/has_one_association.rb +71 -52
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +169 -180
  31. data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +97 -104
  35. data/lib/active_record/associations/preloader/association.rb +109 -97
  36. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  37. data/lib/active_record/associations/singular_association.rb +12 -45
  38. data/lib/active_record/associations/through_association.rb +27 -15
  39. data/lib/active_record/attribute_assignment.rb +55 -60
  40. data/lib/active_record/attribute_methods.rb +111 -141
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
  42. data/lib/active_record/attribute_methods/dirty.rb +172 -112
  43. data/lib/active_record/attribute_methods/primary_key.rb +88 -91
  44. data/lib/active_record/attribute_methods/query.rb +6 -8
  45. data/lib/active_record/attribute_methods/read.rb +18 -50
  46. data/lib/active_record/attribute_methods/serialization.rb +38 -10
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
  48. data/lib/active_record/attribute_methods/write.rb +25 -32
  49. data/lib/active_record/attributes.rb +69 -31
  50. data/lib/active_record/autosave_association.rb +102 -66
  51. data/lib/active_record/base.rb +16 -25
  52. data/lib/active_record/callbacks.rb +202 -43
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -12
  55. data/lib/active_record/connection_adapters.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
  69. data/lib/active_record/connection_adapters/column.rb +55 -13
  70. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  71. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +79 -49
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -56
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +20 -12
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
  82. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  83. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
  85. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
  86. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  90. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -6
  93. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
  95. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  98. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  106. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
  107. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  109. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  110. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +98 -38
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +426 -324
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
  121. data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
  123. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  124. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -6
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +282 -290
  131. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  132. data/lib/active_record/connection_handling.rb +287 -45
  133. data/lib/active_record/core.rb +385 -181
  134. data/lib/active_record/counter_cache.rb +60 -28
  135. data/lib/active_record/database_configurations.rb +272 -0
  136. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  137. data/lib/active_record/database_configurations/database_config.rb +80 -0
  138. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  139. data/lib/active_record/database_configurations/url_config.rb +53 -0
  140. data/lib/active_record/delegated_type.rb +209 -0
  141. data/lib/active_record/destroy_association_async_job.rb +36 -0
  142. data/lib/active_record/dynamic_matchers.rb +87 -87
  143. data/lib/active_record/enum.rb +122 -47
  144. data/lib/active_record/errors.rb +153 -22
  145. data/lib/active_record/explain.rb +13 -8
  146. data/lib/active_record/explain_registry.rb +3 -1
  147. data/lib/active_record/explain_subscriber.rb +9 -4
  148. data/lib/active_record/fixture_set/file.rb +20 -22
  149. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  150. data/lib/active_record/fixture_set/render_context.rb +17 -0
  151. data/lib/active_record/fixture_set/table_row.rb +152 -0
  152. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  153. data/lib/active_record/fixtures.rb +246 -507
  154. data/lib/active_record/gem_version.rb +6 -4
  155. data/lib/active_record/inheritance.rb +168 -95
  156. data/lib/active_record/insert_all.rb +208 -0
  157. data/lib/active_record/integration.rb +114 -25
  158. data/lib/active_record/internal_metadata.rb +30 -24
  159. data/lib/active_record/legacy_yaml_adapter.rb +11 -5
  160. data/lib/active_record/locking/optimistic.rb +81 -85
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +68 -31
  163. data/lib/active_record/middleware/database_selector.rb +77 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  166. data/lib/active_record/migration.rb +439 -342
  167. data/lib/active_record/migration/command_recorder.rb +152 -98
  168. data/lib/active_record/migration/compatibility.rb +229 -60
  169. data/lib/active_record/migration/join_table.rb +8 -7
  170. data/lib/active_record/model_schema.rb +230 -122
  171. data/lib/active_record/nested_attributes.rb +213 -203
  172. data/lib/active_record/no_touching.rb +11 -2
  173. data/lib/active_record/null_relation.rb +12 -34
  174. data/lib/active_record/persistence.rb +471 -97
  175. data/lib/active_record/query_cache.rb +23 -12
  176. data/lib/active_record/querying.rb +43 -25
  177. data/lib/active_record/railtie.rb +155 -43
  178. data/lib/active_record/railties/console_sandbox.rb +2 -0
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +507 -195
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +245 -269
  183. data/lib/active_record/relation.rb +475 -324
  184. data/lib/active_record/relation/batches.rb +125 -72
  185. data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
  186. data/lib/active_record/relation/calculations.rb +267 -171
  187. data/lib/active_record/relation/delegation.rb +73 -69
  188. data/lib/active_record/relation/finder_methods.rb +238 -248
  189. data/lib/active_record/relation/from_clause.rb +7 -9
  190. data/lib/active_record/relation/merger.rb +95 -77
  191. data/lib/active_record/relation/predicate_builder.rb +109 -110
  192. data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
  193. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  194. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  195. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
  196. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  197. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  198. data/lib/active_record/relation/query_attribute.rb +33 -2
  199. data/lib/active_record/relation/query_methods.rb +654 -374
  200. data/lib/active_record/relation/record_fetch_warning.rb +8 -6
  201. data/lib/active_record/relation/spawn_methods.rb +15 -14
  202. data/lib/active_record/relation/where_clause.rb +171 -109
  203. data/lib/active_record/result.rb +88 -51
  204. data/lib/active_record/runtime_registry.rb +5 -3
  205. data/lib/active_record/sanitization.rb +73 -100
  206. data/lib/active_record/schema.rb +7 -14
  207. data/lib/active_record/schema_dumper.rb +101 -69
  208. data/lib/active_record/schema_migration.rb +16 -12
  209. data/lib/active_record/scoping.rb +20 -20
  210. data/lib/active_record/scoping/default.rb +92 -95
  211. data/lib/active_record/scoping/named.rb +39 -30
  212. data/lib/active_record/secure_token.rb +19 -9
  213. data/lib/active_record/serialization.rb +7 -3
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +80 -29
  216. data/lib/active_record/store.rb +122 -42
  217. data/lib/active_record/suppressor.rb +6 -3
  218. data/lib/active_record/table_metadata.rb +51 -39
  219. data/lib/active_record/tasks/database_tasks.rb +332 -115
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +246 -0
  225. data/lib/active_record/timestamp.rb +70 -38
  226. data/lib/active_record/touch_later.rb +26 -24
  227. data/lib/active_record/transactions.rb +121 -184
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type.rb +29 -17
  230. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  231. data/lib/active_record/type/date.rb +2 -0
  232. data/lib/active_record/type/date_time.rb +2 -0
  233. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  234. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  235. data/lib/active_record/type/internal/timezone.rb +2 -0
  236. data/lib/active_record/type/json.rb +30 -0
  237. data/lib/active_record/type/serialized.rb +20 -9
  238. data/lib/active_record/type/text.rb +11 -0
  239. data/lib/active_record/type/time.rb +12 -1
  240. data/lib/active_record/type/type_map.rb +14 -17
  241. data/lib/active_record/type/unsigned_integer.rb +16 -0
  242. data/lib/active_record/type_caster.rb +4 -2
  243. data/lib/active_record/type_caster/connection.rb +17 -13
  244. data/lib/active_record/type_caster/map.rb +10 -6
  245. data/lib/active_record/validations.rb +8 -5
  246. data/lib/active_record/validations/absence.rb +2 -0
  247. data/lib/active_record/validations/associated.rb +4 -3
  248. data/lib/active_record/validations/length.rb +2 -0
  249. data/lib/active_record/validations/numericality.rb +35 -0
  250. data/lib/active_record/validations/presence.rb +4 -2
  251. data/lib/active_record/validations/uniqueness.rb +52 -45
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/arel.rb +54 -0
  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.rb +70 -0
  269. data/lib/arel/nodes/and.rb +32 -0
  270. data/lib/arel/nodes/ascending.rb +23 -0
  271. data/lib/arel/nodes/binary.rb +126 -0
  272. data/lib/arel/nodes/bind_param.rb +44 -0
  273. data/lib/arel/nodes/case.rb +55 -0
  274. data/lib/arel/nodes/casted.rb +62 -0
  275. data/lib/arel/nodes/comment.rb +29 -0
  276. data/lib/arel/nodes/count.rb +12 -0
  277. data/lib/arel/nodes/delete_statement.rb +45 -0
  278. data/lib/arel/nodes/descending.rb +23 -0
  279. data/lib/arel/nodes/equality.rb +15 -0
  280. data/lib/arel/nodes/extract.rb +24 -0
  281. data/lib/arel/nodes/false.rb +16 -0
  282. data/lib/arel/nodes/full_outer_join.rb +8 -0
  283. data/lib/arel/nodes/function.rb +44 -0
  284. data/lib/arel/nodes/grouping.rb +11 -0
  285. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  286. data/lib/arel/nodes/in.rb +15 -0
  287. data/lib/arel/nodes/infix_operation.rb +92 -0
  288. data/lib/arel/nodes/inner_join.rb +8 -0
  289. data/lib/arel/nodes/insert_statement.rb +37 -0
  290. data/lib/arel/nodes/join_source.rb +20 -0
  291. data/lib/arel/nodes/matches.rb +18 -0
  292. data/lib/arel/nodes/named_function.rb +23 -0
  293. data/lib/arel/nodes/node.rb +51 -0
  294. data/lib/arel/nodes/node_expression.rb +13 -0
  295. data/lib/arel/nodes/ordering.rb +27 -0
  296. data/lib/arel/nodes/outer_join.rb +8 -0
  297. data/lib/arel/nodes/over.rb +15 -0
  298. data/lib/arel/nodes/regexp.rb +16 -0
  299. data/lib/arel/nodes/right_outer_join.rb +8 -0
  300. data/lib/arel/nodes/select_core.rb +67 -0
  301. data/lib/arel/nodes/select_statement.rb +41 -0
  302. data/lib/arel/nodes/sql_literal.rb +19 -0
  303. data/lib/arel/nodes/string_join.rb +11 -0
  304. data/lib/arel/nodes/table_alias.rb +31 -0
  305. data/lib/arel/nodes/terminal.rb +16 -0
  306. data/lib/arel/nodes/true.rb +16 -0
  307. data/lib/arel/nodes/unary.rb +44 -0
  308. data/lib/arel/nodes/unary_operation.rb +20 -0
  309. data/lib/arel/nodes/unqualified_column.rb +22 -0
  310. data/lib/arel/nodes/update_statement.rb +41 -0
  311. data/lib/arel/nodes/values_list.rb +9 -0
  312. data/lib/arel/nodes/window.rb +126 -0
  313. data/lib/arel/nodes/with.rb +11 -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.rb +13 -0
  321. data/lib/arel/visitors/dot.rb +308 -0
  322. data/lib/arel/visitors/mysql.rb +93 -0
  323. data/lib/arel/visitors/postgresql.rb +120 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +899 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/rails/generators/active_record.rb +7 -5
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration.rb +22 -3
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
  333. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
  334. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
  335. data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
  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 → model.rb.tt} +10 -1
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. metadata +141 -57
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  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 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute.rb +0 -213
  348. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  349. data/lib/active_record/attribute_decorators.rb +0 -67
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
  355. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
  356. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  359. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -17
  360. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  361. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  362. data/lib/active_record/relation/where_clause_factory.rb +0 -38
  363. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record No Touching
3
5
  module NoTouching
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  module ClassMethods
7
- # Lets you selectively disable calls to `touch` for the
9
+ # Lets you selectively disable calls to +touch+ for the
8
10
  # duration of a block.
9
11
  #
10
12
  # ==== Examples
@@ -41,6 +43,13 @@ module ActiveRecord
41
43
  end
42
44
  end
43
45
 
46
+ # Returns +true+ if the class has +no_touching+ set, +false+ otherwise.
47
+ #
48
+ # Project.no_touching do
49
+ # Project.first.no_touching? # true
50
+ # Message.first.no_touching? # false
51
+ # end
52
+ #
44
53
  def no_touching?
45
54
  NoTouching.applied_to?(self.class)
46
55
  end
@@ -49,7 +58,7 @@ module ActiveRecord
49
58
  super unless no_touching?
50
59
  end
51
60
 
52
- def touch(*) # :nodoc:
61
+ def touch(*, **) # :nodoc:
53
62
  super unless no_touching?
54
63
  end
55
64
  end
@@ -1,14 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module NullRelation # :nodoc:
3
- def exec_queries
4
- @records = [].freeze
5
- end
6
-
7
5
  def pluck(*column_names)
8
6
  []
9
7
  end
10
8
 
11
- def delete_all(_conditions = nil)
9
+ def delete_all
12
10
  0
13
11
  end
14
12
 
@@ -20,10 +18,6 @@ module ActiveRecord
20
18
  0
21
19
  end
22
20
 
23
- def size
24
- calculate :size, nil
25
- end
26
-
27
21
  def empty?
28
22
  true
29
23
  end
@@ -48,33 +42,12 @@ module ActiveRecord
48
42
  ""
49
43
  end
50
44
 
51
- def count(*)
52
- calculate :count, nil
53
- end
54
-
55
- def sum(*)
56
- calculate :sum, nil
57
- end
58
-
59
- def average(*)
60
- calculate :average, nil
61
- end
62
-
63
- def minimum(*)
64
- calculate :minimum, nil
65
- end
66
-
67
- def maximum(*)
68
- calculate :maximum, nil
69
- end
70
-
71
45
  def calculate(operation, _column_name)
72
- if [:count, :sum, :size].include? operation
46
+ case operation
47
+ when :count, :sum
73
48
  group_values.any? ? Hash.new : 0
74
- elsif [:average, :minimum, :maximum].include?(operation) && group_values.any?
75
- Hash.new
76
- else
77
- nil
49
+ when :average, :minimum, :maximum
50
+ group_values.any? ? Hash.new : nil
78
51
  end
79
52
  end
80
53
 
@@ -85,5 +58,10 @@ module ActiveRecord
85
58
  def or(other)
86
59
  other.spawn
87
60
  end
61
+
62
+ private
63
+ def exec_queries
64
+ @records = [].freeze
65
+ end
88
66
  end
89
67
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/insert_all"
4
+
1
5
  module ActiveRecord
2
6
  # = Active Record \Persistence
3
7
  module Persistence
@@ -53,6 +57,192 @@ module ActiveRecord
53
57
  end
54
58
  end
55
59
 
60
+ # Inserts a single record into the database in a single SQL INSERT
61
+ # statement. It does not instantiate any models nor does it trigger
62
+ # Active Record callbacks or validations. Though passed values
63
+ # go through Active Record's type casting and serialization.
64
+ #
65
+ # See <tt>ActiveRecord::Persistence#insert_all</tt> for documentation.
66
+ def insert(attributes, returning: nil, unique_by: nil)
67
+ insert_all([ attributes ], returning: returning, unique_by: unique_by)
68
+ end
69
+
70
+ # Inserts multiple records into the database in a single SQL INSERT
71
+ # statement. It does not instantiate any models nor does it trigger
72
+ # Active Record callbacks or validations. Though passed values
73
+ # go through Active Record's type casting and serialization.
74
+ #
75
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
76
+ # the attributes for a single row and must have the same keys.
77
+ #
78
+ # Rows are considered to be unique by every unique index on the table. Any
79
+ # duplicate rows are skipped.
80
+ # Override with <tt>:unique_by</tt> (see below).
81
+ #
82
+ # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
83
+ # <tt>:returning</tt> (see below).
84
+ #
85
+ # ==== Options
86
+ #
87
+ # [:returning]
88
+ # (PostgreSQL only) An array of attributes to return for all successfully
89
+ # inserted records, which by default is the primary key.
90
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
91
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
92
+ # clause entirely.
93
+ #
94
+ # [:unique_by]
95
+ # (PostgreSQL and SQLite only) By default rows are considered to be unique
96
+ # by every unique index on the table. Any duplicate rows are skipped.
97
+ #
98
+ # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
99
+ #
100
+ # Consider a Book model where no duplicate ISBNs make sense, but if any
101
+ # row has an existing id, or is not unique by another unique index,
102
+ # <tt>ActiveRecord::RecordNotUnique</tt> is raised.
103
+ #
104
+ # Unique indexes can be identified by columns or name:
105
+ #
106
+ # unique_by: :isbn
107
+ # unique_by: %i[ author_id name ]
108
+ # unique_by: :index_books_on_isbn
109
+ #
110
+ # Because it relies on the index information from the database
111
+ # <tt>:unique_by</tt> is recommended to be paired with
112
+ # Active Record's schema_cache.
113
+ #
114
+ # ==== Example
115
+ #
116
+ # # Insert records and skip inserting any duplicates.
117
+ # # Here "Eloquent Ruby" is skipped because its id is not unique.
118
+ #
119
+ # Book.insert_all([
120
+ # { id: 1, title: "Rework", author: "David" },
121
+ # { id: 1, title: "Eloquent Ruby", author: "Russ" }
122
+ # ])
123
+ def insert_all(attributes, returning: nil, unique_by: nil)
124
+ InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by).execute
125
+ end
126
+
127
+ # Inserts a single record into the database in a single SQL INSERT
128
+ # statement. It does not instantiate any models nor does it trigger
129
+ # Active Record callbacks or validations. Though passed values
130
+ # go through Active Record's type casting and serialization.
131
+ #
132
+ # See <tt>ActiveRecord::Persistence#insert_all!</tt> for more.
133
+ def insert!(attributes, returning: nil)
134
+ insert_all!([ attributes ], returning: returning)
135
+ end
136
+
137
+ # Inserts multiple records into the database in a single SQL INSERT
138
+ # statement. It does not instantiate any models nor does it trigger
139
+ # Active Record callbacks or validations. Though passed values
140
+ # go through Active Record's type casting and serialization.
141
+ #
142
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
143
+ # the attributes for a single row and must have the same keys.
144
+ #
145
+ # Raises <tt>ActiveRecord::RecordNotUnique</tt> if any rows violate a
146
+ # unique index on the table. In that case, no rows are inserted.
147
+ #
148
+ # To skip duplicate rows, see <tt>ActiveRecord::Persistence#insert_all</tt>.
149
+ # To replace them, see <tt>ActiveRecord::Persistence#upsert_all</tt>.
150
+ #
151
+ # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
152
+ # <tt>:returning</tt> (see below).
153
+ #
154
+ # ==== Options
155
+ #
156
+ # [:returning]
157
+ # (PostgreSQL only) An array of attributes to return for all successfully
158
+ # inserted records, which by default is the primary key.
159
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
160
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
161
+ # clause entirely.
162
+ #
163
+ # ==== Examples
164
+ #
165
+ # # Insert multiple records
166
+ # Book.insert_all!([
167
+ # { title: "Rework", author: "David" },
168
+ # { title: "Eloquent Ruby", author: "Russ" }
169
+ # ])
170
+ #
171
+ # # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
172
+ # # does not have a unique id.
173
+ # Book.insert_all!([
174
+ # { id: 1, title: "Rework", author: "David" },
175
+ # { id: 1, title: "Eloquent Ruby", author: "Russ" }
176
+ # ])
177
+ def insert_all!(attributes, returning: nil)
178
+ InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning).execute
179
+ end
180
+
181
+ # Updates or inserts (upserts) a single record into the database in a
182
+ # single SQL INSERT statement. It does not instantiate any models nor does
183
+ # it trigger Active Record callbacks or validations. Though passed values
184
+ # go through Active Record's type casting and serialization.
185
+ #
186
+ # See <tt>ActiveRecord::Persistence#upsert_all</tt> for documentation.
187
+ def upsert(attributes, returning: nil, unique_by: nil)
188
+ upsert_all([ attributes ], returning: returning, unique_by: unique_by)
189
+ end
190
+
191
+ # Updates or inserts (upserts) multiple records into the database in a
192
+ # single SQL INSERT statement. It does not instantiate any models nor does
193
+ # it trigger Active Record callbacks or validations. Though passed values
194
+ # go through Active Record's type casting and serialization.
195
+ #
196
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
197
+ # the attributes for a single row and must have the same keys.
198
+ #
199
+ # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
200
+ # <tt>:returning</tt> (see below).
201
+ #
202
+ # ==== Options
203
+ #
204
+ # [:returning]
205
+ # (PostgreSQL only) An array of attributes to return for all successfully
206
+ # inserted records, which by default is the primary key.
207
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
208
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
209
+ # clause entirely.
210
+ #
211
+ # [:unique_by]
212
+ # (PostgreSQL and SQLite only) By default rows are considered to be unique
213
+ # by every unique index on the table. Any duplicate rows are skipped.
214
+ #
215
+ # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
216
+ #
217
+ # Consider a Book model where no duplicate ISBNs make sense, but if any
218
+ # row has an existing id, or is not unique by another unique index,
219
+ # <tt>ActiveRecord::RecordNotUnique</tt> is raised.
220
+ #
221
+ # Unique indexes can be identified by columns or name:
222
+ #
223
+ # unique_by: :isbn
224
+ # unique_by: %i[ author_id name ]
225
+ # unique_by: :index_books_on_isbn
226
+ #
227
+ # Because it relies on the index information from the database
228
+ # <tt>:unique_by</tt> is recommended to be paired with
229
+ # Active Record's schema_cache.
230
+ #
231
+ # ==== Examples
232
+ #
233
+ # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
234
+ # # Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
235
+ #
236
+ # Book.upsert_all([
237
+ # { title: "Rework", author: "David", isbn: "1" },
238
+ # { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
239
+ # ], unique_by: :isbn)
240
+ #
241
+ # Book.find_by(isbn: "1").title # => "Eloquent Ruby"
242
+ def upsert_all(attributes, returning: nil, unique_by: nil)
243
+ InsertAll.new(self, attributes, on_duplicate: :update, returning: returning, unique_by: unique_by).execute
244
+ end
245
+
56
246
  # Given an attributes hash, +instantiate+ returns a new instance of
57
247
  # the appropriate class. Accepts only keys as strings.
58
248
  #
@@ -65,11 +255,154 @@ module ActiveRecord
65
255
  # how this "single-table" inheritance mapping is implemented.
66
256
  def instantiate(attributes, column_types = {}, &block)
67
257
  klass = discriminate_class_for_record(attributes)
68
- attributes = klass.attributes_builder.build_from_database(attributes, column_types)
69
- klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
258
+ instantiate_instance_of(klass, attributes, column_types, &block)
259
+ end
260
+
261
+ # Updates an object (or multiple objects) and saves it to the database, if validations pass.
262
+ # The resulting object is returned whether the object was saved successfully to the database or not.
263
+ #
264
+ # ==== Parameters
265
+ #
266
+ # * +id+ - This should be the id or an array of ids to be updated.
267
+ # * +attributes+ - This should be a hash of attributes or an array of hashes.
268
+ #
269
+ # ==== Examples
270
+ #
271
+ # # Updates one record
272
+ # Person.update(15, user_name: "Samuel", group: "expert")
273
+ #
274
+ # # Updates multiple records
275
+ # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
276
+ # Person.update(people.keys, people.values)
277
+ #
278
+ # # Updates multiple records from the result of a relation
279
+ # people = Person.where(group: "expert")
280
+ # people.update(group: "masters")
281
+ #
282
+ # Note: Updating a large number of records will run an UPDATE
283
+ # query for each record, which may cause a performance issue.
284
+ # When running callbacks is not needed for each record update,
285
+ # it is preferred to use {update_all}[rdoc-ref:Relation#update_all]
286
+ # for updating all records in a single query.
287
+ def update(id = :all, attributes)
288
+ if id.is_a?(Array)
289
+ id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
290
+ object.update(attributes[idx])
291
+ }
292
+ elsif id == :all
293
+ all.each { |record| record.update(attributes) }
294
+ else
295
+ if ActiveRecord::Base === id
296
+ raise ArgumentError,
297
+ "You are passing an instance of ActiveRecord::Base to `update`. " \
298
+ "Please pass the id of the object by calling `.id`."
299
+ end
300
+ object = find(id)
301
+ object.update(attributes)
302
+ object
303
+ end
304
+ end
305
+
306
+ # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
307
+ # therefore all callbacks and filters are fired off before the object is deleted. This method is
308
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
309
+ #
310
+ # This essentially finds the object (or multiple objects) with the given id, creates a new object
311
+ # from the attributes, and then calls destroy on it.
312
+ #
313
+ # ==== Parameters
314
+ #
315
+ # * +id+ - This should be the id or an array of ids to be destroyed.
316
+ #
317
+ # ==== Examples
318
+ #
319
+ # # Destroy a single object
320
+ # Todo.destroy(1)
321
+ #
322
+ # # Destroy multiple objects
323
+ # todos = [1,2,3]
324
+ # Todo.destroy(todos)
325
+ def destroy(id)
326
+ if id.is_a?(Array)
327
+ find(id).each(&:destroy)
328
+ else
329
+ find(id).destroy
330
+ end
331
+ end
332
+
333
+ # Deletes the row with a primary key matching the +id+ argument, using an
334
+ # SQL +DELETE+ statement, and returns the number of rows deleted. Active
335
+ # Record objects are not instantiated, so the object's callbacks are not
336
+ # executed, including any <tt>:dependent</tt> association options.
337
+ #
338
+ # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
339
+ #
340
+ # Note: Although it is often much faster than the alternative, #destroy,
341
+ # skipping callbacks might bypass business logic in your application
342
+ # that ensures referential integrity or performs other essential jobs.
343
+ #
344
+ # ==== Examples
345
+ #
346
+ # # Delete a single row
347
+ # Todo.delete(1)
348
+ #
349
+ # # Delete multiple rows
350
+ # Todo.delete([2,3,4])
351
+ def delete(id_or_array)
352
+ delete_by(primary_key => id_or_array)
353
+ end
354
+
355
+ def _insert_record(values) # :nodoc:
356
+ primary_key = self.primary_key
357
+ primary_key_value = nil
358
+
359
+ if primary_key && Hash === values
360
+ primary_key_value = values[primary_key]
361
+
362
+ if !primary_key_value && prefetch_primary_key?
363
+ primary_key_value = next_sequence_value
364
+ values[primary_key] = primary_key_value
365
+ end
366
+ end
367
+
368
+ if values.empty?
369
+ im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
370
+ im.into arel_table
371
+ else
372
+ im = arel_table.compile_insert(_substitute_values(values))
373
+ end
374
+
375
+ connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
376
+ end
377
+
378
+ def _update_record(values, constraints) # :nodoc:
379
+ constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
380
+
381
+ um = arel_table.where(
382
+ constraints.reduce(&:and)
383
+ ).compile_update(_substitute_values(values), primary_key)
384
+
385
+ connection.update(um, "#{self} Update")
386
+ end
387
+
388
+ def _delete_record(constraints) # :nodoc:
389
+ constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
390
+
391
+ dm = Arel::DeleteManager.new
392
+ dm.from(arel_table)
393
+ dm.wheres = constraints
394
+
395
+ connection.delete(dm, "#{self} Destroy")
70
396
  end
71
397
 
72
398
  private
399
+ # Given a class, an attributes hash, +instantiate_instance_of+ returns a
400
+ # new instance of the class. Accepts only keys as strings.
401
+ def instantiate_instance_of(klass, attributes, column_types = {}, &block)
402
+ attributes = klass.attributes_builder.build_from_database(attributes, column_types)
403
+ klass.allocate.init_with_attributes(attributes, &block)
404
+ end
405
+
73
406
  # Called by +instantiate+ to decide which class to use for a new
74
407
  # record instance.
75
408
  #
@@ -78,31 +411,43 @@ module ActiveRecord
78
411
  def discriminate_class_for_record(record)
79
412
  self
80
413
  end
414
+
415
+ def _substitute_values(values)
416
+ values.map do |name, value|
417
+ attr = arel_table[name]
418
+ bind = predicate_builder.build_bind_attribute(attr.name, value)
419
+ [attr, bind]
420
+ end
421
+ end
81
422
  end
82
423
 
83
424
  # Returns true if this object hasn't been saved yet -- that is, a record
84
425
  # for the object doesn't exist in the database yet; otherwise, returns false.
85
426
  def new_record?
86
- sync_with_transaction_state
87
427
  @new_record
88
428
  end
89
429
 
430
+ # Returns true if this object was just created -- that is, prior to the last
431
+ # save, the object didn't exist in the database and new_record? would have
432
+ # returned true.
433
+ def previously_new_record?
434
+ @previously_new_record
435
+ end
436
+
90
437
  # Returns true if this object has been destroyed, otherwise returns false.
91
438
  def destroyed?
92
- sync_with_transaction_state
93
439
  @destroyed
94
440
  end
95
441
 
96
442
  # Returns true if the record is persisted, i.e. it's not a new record and it was
97
443
  # not destroyed, otherwise returns false.
98
444
  def persisted?
99
- sync_with_transaction_state
100
445
  !(@new_record || @destroyed)
101
446
  end
102
447
 
103
448
  ##
104
449
  # :call-seq:
105
- # save(*args)
450
+ # save(**options)
106
451
  #
107
452
  # Saves the model.
108
453
  #
@@ -111,7 +456,7 @@ module ActiveRecord
111
456
  #
112
457
  # By default, save always runs validations. If any of them fail the action
113
458
  # is cancelled and #save returns +false+, and the record won't be saved. However, if you supply
114
- # validate: false, validations are bypassed altogether. See
459
+ # <tt>validate: false</tt>, validations are bypassed altogether. See
115
460
  # ActiveRecord::Validations for more information.
116
461
  #
117
462
  # By default, #save also sets the +updated_at+/+updated_on+ attributes to
@@ -125,15 +470,15 @@ module ActiveRecord
125
470
  #
126
471
  # Attributes marked as readonly are silently ignored if the record is
127
472
  # being updated.
128
- def save(*args, &block)
129
- create_or_update(*args, &block)
473
+ def save(**options, &block)
474
+ create_or_update(**options, &block)
130
475
  rescue ActiveRecord::RecordInvalid
131
476
  false
132
477
  end
133
478
 
134
479
  ##
135
480
  # :call-seq:
136
- # save!(*args)
481
+ # save!(**options)
137
482
  #
138
483
  # Saves the model.
139
484
  #
@@ -142,7 +487,7 @@ module ActiveRecord
142
487
  #
143
488
  # By default, #save! always runs validations. If any of them fail
144
489
  # ActiveRecord::RecordInvalid gets raised, and the record won't be saved. However, if you supply
145
- # validate: false, validations are bypassed altogether. See
490
+ # <tt>validate: false</tt>, validations are bypassed altogether. See
146
491
  # ActiveRecord::Validations for more information.
147
492
  #
148
493
  # By default, #save! also sets the +updated_at+/+updated_on+ attributes to
@@ -156,8 +501,10 @@ module ActiveRecord
156
501
  #
157
502
  # Attributes marked as readonly are silently ignored if the record is
158
503
  # being updated.
159
- def save!(*args, &block)
160
- create_or_update(*args, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
504
+ #
505
+ # Unless an error is raised, returns true.
506
+ def save!(**options, &block)
507
+ create_or_update(**options, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
161
508
  end
162
509
 
163
510
  # Deletes the record in the database and freezes this instance to
@@ -171,9 +518,9 @@ module ActiveRecord
171
518
  #
172
519
  # To enforce the object's +before_destroy+ and +after_destroy+
173
520
  # callbacks or any <tt>:dependent</tt> association
174
- # options, use <tt>#destroy</tt>.
521
+ # options, use #destroy.
175
522
  def delete
176
- self.class.delete(id) if persisted?
523
+ _delete_row if persisted?
177
524
  @destroyed = true
178
525
  freeze
179
526
  end
@@ -186,10 +533,13 @@ module ActiveRecord
186
533
  # and #destroy returns +false+.
187
534
  # See ActiveRecord::Callbacks for further details.
188
535
  def destroy
189
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
536
+ _raise_readonly_record_error if readonly?
190
537
  destroy_associations
191
- self.class.connection.add_transaction_record(self)
192
- destroy_row if persisted?
538
+ @_trigger_destroy_callback = if persisted?
539
+ destroy_row > 0
540
+ else
541
+ true
542
+ end
193
543
  @destroyed = true
194
544
  freeze
195
545
  end
@@ -218,13 +568,16 @@ module ActiveRecord
218
568
  # Any change to the attributes on either instance will affect both instances.
219
569
  # If you want to change the sti column as well, use #becomes! instead.
220
570
  def becomes(klass)
221
- became = klass.new
222
- became.instance_variable_set("@attributes", @attributes)
223
- became.instance_variable_set("@mutation_tracker", @mutation_tracker) if defined?(@mutation_tracker)
224
- became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
225
- became.instance_variable_set("@new_record", new_record?)
226
- became.instance_variable_set("@destroyed", destroyed?)
227
- became.errors.copy!(errors)
571
+ became = klass.allocate
572
+
573
+ became.send(:initialize) do |becoming|
574
+ becoming.instance_variable_set(:@attributes, @attributes)
575
+ becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
576
+ becoming.instance_variable_set(:@new_record, new_record?)
577
+ becoming.instance_variable_set(:@destroyed, destroyed?)
578
+ becoming.errors.copy!(errors)
579
+ end
580
+
228
581
  became
229
582
  end
230
583
 
@@ -261,7 +614,7 @@ module ActiveRecord
261
614
  verify_readonly_attribute(name)
262
615
  public_send("#{name}=", value)
263
616
 
264
- changed? ? save(validate: false) : true
617
+ save(validate: false)
265
618
  end
266
619
 
267
620
  # Updates the attributes of the model from the passed-in hash and saves the
@@ -276,8 +629,6 @@ module ActiveRecord
276
629
  end
277
630
  end
278
631
 
279
- alias update_attributes update
280
-
281
632
  # Updates its receiver just like #update but calls #save! instead
282
633
  # of +save+, so an exception is raised if the record is invalid and saving will fail.
283
634
  def update!(attributes)
@@ -289,8 +640,6 @@ module ActiveRecord
289
640
  end
290
641
  end
291
642
 
292
- alias update_attributes! update!
293
-
294
643
  # Equivalent to <code>update_columns(name => value)</code>.
295
644
  def update_column(name, value)
296
645
  update_columns(name => value)
@@ -316,17 +665,23 @@ module ActiveRecord
316
665
  raise ActiveRecordError, "cannot update a new record" if new_record?
317
666
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
318
667
 
319
- attributes.each_key do |key|
320
- verify_readonly_attribute(key.to_s)
668
+ attributes = attributes.transform_keys do |key|
669
+ name = key.to_s
670
+ name = self.class.attribute_aliases[name] || name
671
+ verify_readonly_attribute(name) || name
321
672
  end
322
673
 
323
- updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)
324
-
674
+ id_in_database = self.id_in_database
325
675
  attributes.each do |k, v|
326
- raw_write_attribute(k, v)
676
+ write_attribute_without_type_cast(k, v)
327
677
  end
328
678
 
329
- updated_count == 1
679
+ affected_rows = self.class._update_record(
680
+ attributes,
681
+ @primary_key => id_in_database
682
+ )
683
+
684
+ affected_rows == 1
330
685
  end
331
686
 
332
687
  # Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
@@ -341,12 +696,14 @@ module ActiveRecord
341
696
  # Wrapper around #increment that writes the update to the database.
342
697
  # Only +attribute+ is updated; the record itself is not saved.
343
698
  # This means that any other modified attributes will still be dirty.
344
- # Validations and callbacks are skipped. Returns +self+.
345
- def increment!(attribute, by = 1)
699
+ # Validations and callbacks are skipped. Supports the +touch+ option from
700
+ # +update_counters+, see that for more.
701
+ # Returns +self+.
702
+ def increment!(attribute, by = 1, touch: nil)
346
703
  increment(attribute, by)
347
- change = public_send(attribute) - (attribute_was(attribute.to_s) || 0)
348
- self.class.update_counters(id, attribute => change)
349
- clear_attribute_change(attribute) # eww
704
+ change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0)
705
+ self.class.update_counters(id, attribute => change, touch: touch)
706
+ public_send(:"clear_#{attribute}_change")
350
707
  self
351
708
  end
352
709
 
@@ -360,9 +717,11 @@ module ActiveRecord
360
717
  # Wrapper around #decrement that writes the update to the database.
361
718
  # Only +attribute+ is updated; the record itself is not saved.
362
719
  # This means that any other modified attributes will still be dirty.
363
- # Validations and callbacks are skipped. Returns +self+.
364
- def decrement!(attribute, by = 1)
365
- increment!(attribute, -by)
720
+ # Validations and callbacks are skipped. Supports the +touch+ option from
721
+ # +update_counters+, see that for more.
722
+ # Returns +self+.
723
+ def decrement!(attribute, by = 1, touch: nil)
724
+ increment!(attribute, -by, touch: touch)
366
725
  end
367
726
 
368
727
  # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
@@ -392,8 +751,8 @@ module ActiveRecord
392
751
 
393
752
  # Reloads the record from the database.
394
753
  #
395
- # This method finds record by its primary key (which could be assigned manually) and
396
- # modifies the receiver in-place:
754
+ # This method finds the record by its primary key (which could be assigned
755
+ # manually) and modifies the receiver in-place:
397
756
  #
398
757
  # account = Account.new
399
758
  # # => #<Account id: nil, email: nil>
@@ -448,8 +807,9 @@ module ActiveRecord
448
807
  self.class.unscoped { self.class.find(id) }
449
808
  end
450
809
 
451
- @attributes = fresh_object.instance_variable_get('@attributes')
810
+ @attributes = fresh_object.instance_variable_get(:@attributes)
452
811
  @new_record = false
812
+ @previously_new_record = false
453
813
  self
454
814
  end
455
815
 
@@ -488,91 +848,92 @@ module ActiveRecord
488
848
  # ball.touch(:updated_at) # => raises ActiveRecordError
489
849
  #
490
850
  def touch(*names, time: nil)
491
- unless persisted?
492
- raise ActiveRecordError, <<-MSG.squish
493
- cannot touch on a new or destroyed record object. Consider using
494
- persisted?, new_record?, or destroyed? before touching
495
- MSG
496
- end
497
-
498
- time ||= current_time_from_proper_timezone
499
- attributes = timestamp_attributes_for_update_in_model
500
- attributes.concat(names)
501
-
502
- unless attributes.empty?
503
- changes = {}
504
-
505
- attributes.each do |column|
506
- column = column.to_s
507
- changes[column] = write_attribute(column, time)
508
- end
509
-
510
- clear_attribute_changes(changes.keys)
511
- primary_key = self.class.primary_key
512
- scope = self.class.unscoped.where(primary_key => _read_attribute(primary_key))
513
-
514
- if locking_enabled?
515
- locking_column = self.class.locking_column
516
- scope = scope.where(locking_column => _read_attribute(locking_column))
517
- changes[locking_column] = increment_lock
518
- end
851
+ _raise_record_not_touched_error unless persisted?
519
852
 
520
- result = scope.update_all(changes) == 1
853
+ attribute_names = timestamp_attributes_for_update_in_model
854
+ attribute_names |= names.map! do |name|
855
+ name = name.to_s
856
+ self.class.attribute_aliases[name] || name
857
+ end unless names.empty?
521
858
 
522
- if !result && locking_enabled?
523
- raise ActiveRecord::StaleObjectError.new(self, "touch")
524
- end
525
-
526
- result
859
+ unless attribute_names.empty?
860
+ affected_rows = _touch_row(attribute_names, time)
861
+ @_trigger_update_callback = affected_rows == 1
527
862
  else
528
863
  true
529
864
  end
530
865
  end
531
866
 
532
867
  private
533
-
534
868
  # A hook to be overridden by association modules.
535
869
  def destroy_associations
536
870
  end
537
871
 
538
872
  def destroy_row
539
- relation_for_destroy.delete_all
873
+ _delete_row
874
+ end
875
+
876
+ def _delete_row
877
+ self.class._delete_record(@primary_key => id_in_database)
878
+ end
879
+
880
+ def _touch_row(attribute_names, time)
881
+ time ||= current_time_from_proper_timezone
882
+
883
+ attribute_names.each do |attr_name|
884
+ _write_attribute(attr_name, time)
885
+ end
886
+
887
+ _update_row(attribute_names, "touch")
540
888
  end
541
889
 
542
- def relation_for_destroy
543
- self.class.unscoped.where(self.class.primary_key => id)
890
+ def _update_row(attribute_names, attempted_action = "update")
891
+ self.class._update_record(
892
+ attributes_with_values(attribute_names),
893
+ @primary_key => id_in_database
894
+ )
544
895
  end
545
896
 
546
- def create_or_update(*args, &block)
547
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
548
- result = new_record? ? _create_record(&block) : _update_record(*args, &block)
897
+ def create_or_update(**, &block)
898
+ _raise_readonly_record_error if readonly?
899
+ return false if destroyed?
900
+ result = new_record? ? _create_record(&block) : _update_record(&block)
549
901
  result != false
550
902
  end
551
903
 
552
904
  # Updates the associated record with values matching those of the instance attributes.
553
905
  # Returns the number of affected rows.
554
906
  def _update_record(attribute_names = self.attribute_names)
555
- attributes_values = arel_attributes_with_values_for_update(attribute_names)
556
- if attributes_values.empty?
557
- rows_affected = 0
907
+ attribute_names = attributes_for_update(attribute_names)
908
+
909
+ if attribute_names.empty?
910
+ affected_rows = 0
911
+ @_trigger_update_callback = true
558
912
  else
559
- rows_affected = self.class.unscoped._update_record attributes_values, id, id_was
913
+ affected_rows = _update_row(attribute_names)
914
+ @_trigger_update_callback = affected_rows == 1
560
915
  end
561
916
 
917
+ @previously_new_record = false
918
+
562
919
  yield(self) if block_given?
563
920
 
564
- rows_affected
921
+ affected_rows
565
922
  end
566
923
 
567
924
  # Creates a record with values matching those of the instance attributes
568
925
  # and returns its id.
569
926
  def _create_record(attribute_names = self.attribute_names)
570
- attributes_values = arel_attributes_with_values_for_create(attribute_names)
927
+ attribute_names = attributes_for_create(attribute_names)
928
+
929
+ new_id = self.class._insert_record(
930
+ attributes_with_values(attribute_names)
931
+ )
571
932
 
572
- new_id = self.class.unscoped.insert attributes_values
573
- self.id ||= new_id if self.class.primary_key
933
+ self.id ||= new_id if @primary_key
574
934
 
575
935
  @new_record = false
936
+ @previously_new_record = true
576
937
 
577
938
  yield(self) if block_given?
578
939
 
@@ -580,7 +941,7 @@ module ActiveRecord
580
941
  end
581
942
 
582
943
  def verify_readonly_attribute(name)
583
- raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
944
+ raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
584
945
  end
585
946
 
586
947
  def _raise_record_not_destroyed
@@ -590,6 +951,19 @@ module ActiveRecord
590
951
  @_association_destroy_exception = nil
591
952
  end
592
953
 
954
+ def _raise_readonly_record_error
955
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly"
956
+ end
957
+
958
+ def _raise_record_not_touched_error
959
+ raise ActiveRecordError, <<~MSG.squish
960
+ Cannot touch on a new or destroyed record object. Consider using
961
+ persisted?, new_record?, or destroyed? before touching.
962
+ MSG
963
+ end
964
+
965
+ # The name of the method used to touch a +belongs_to+ association when the
966
+ # +:touch+ option is used.
593
967
  def belongs_to_touch_method
594
968
  :touch
595
969
  end