activerecord 5.2.6 → 6.1.3.2

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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1038 -571
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +13 -12
  7. data/lib/active_record/aggregations.rb +9 -8
  8. data/lib/active_record/association_relation.rb +30 -10
  9. data/lib/active_record/associations.rb +137 -25
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +95 -42
  12. data/lib/active_record/associations/association_scope.rb +23 -21
  13. data/lib/active_record/associations/belongs_to_association.rb +54 -46
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  15. data/lib/active_record/associations/builder/association.rb +45 -22
  16. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  17. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  19. data/lib/active_record/associations/builder/has_many.rb +8 -2
  20. data/lib/active_record/associations/builder/has_one.rb +33 -2
  21. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  22. data/lib/active_record/associations/collection_association.rb +31 -29
  23. data/lib/active_record/associations/collection_proxy.rb +25 -21
  24. data/lib/active_record/associations/foreign_association.rb +20 -0
  25. data/lib/active_record/associations/has_many_association.rb +26 -13
  26. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  27. data/lib/active_record/associations/has_one_association.rb +43 -31
  28. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  31. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/preloader/association.rb +71 -43
  34. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  35. data/lib/active_record/associations/singular_association.rb +3 -17
  36. data/lib/active_record/associations/through_association.rb +1 -1
  37. data/lib/active_record/attribute_assignment.rb +17 -19
  38. data/lib/active_record/attribute_methods.rb +81 -143
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  42. data/lib/active_record/attribute_methods/query.rb +4 -8
  43. data/lib/active_record/attribute_methods/read.rb +14 -56
  44. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  46. data/lib/active_record/attribute_methods/write.rb +18 -34
  47. data/lib/active_record/attributes.rb +46 -9
  48. data/lib/active_record/autosave_association.rb +57 -42
  49. data/lib/active_record/base.rb +4 -17
  50. data/lib/active_record/callbacks.rb +158 -43
  51. data/lib/active_record/coders/yaml_column.rb +1 -2
  52. data/lib/active_record/connection_adapters.rb +50 -0
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  58. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  60. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -90
  61. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  63. data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
  64. data/lib/active_record/connection_adapters/abstract_adapter.rb +228 -98
  65. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  66. data/lib/active_record/connection_adapters/column.rb +30 -12
  67. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  68. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  69. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
  71. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  77. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  79. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  80. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
  83. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  99. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  101. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  102. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  103. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  104. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  105. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  106. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  107. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  108. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
  109. data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
  110. data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
  111. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  112. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  113. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  114. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  116. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  117. data/lib/active_record/connection_handling.rb +293 -33
  118. data/lib/active_record/core.rb +323 -97
  119. data/lib/active_record/counter_cache.rb +8 -30
  120. data/lib/active_record/database_configurations.rb +272 -0
  121. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  122. data/lib/active_record/database_configurations/database_config.rb +80 -0
  123. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  124. data/lib/active_record/database_configurations/url_config.rb +53 -0
  125. data/lib/active_record/delegated_type.rb +209 -0
  126. data/lib/active_record/destroy_association_async_job.rb +36 -0
  127. data/lib/active_record/dynamic_matchers.rb +3 -4
  128. data/lib/active_record/enum.rb +111 -37
  129. data/lib/active_record/errors.rb +62 -19
  130. data/lib/active_record/explain.rb +10 -6
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +10 -17
  133. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  134. data/lib/active_record/fixture_set/render_context.rb +17 -0
  135. data/lib/active_record/fixture_set/table_row.rb +152 -0
  136. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  137. data/lib/active_record/fixtures.rb +200 -481
  138. data/lib/active_record/gem_version.rb +4 -4
  139. data/lib/active_record/inheritance.rb +53 -24
  140. data/lib/active_record/insert_all.rb +208 -0
  141. data/lib/active_record/integration.rb +67 -17
  142. data/lib/active_record/internal_metadata.rb +26 -9
  143. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  144. data/lib/active_record/locking/optimistic.rb +37 -23
  145. data/lib/active_record/locking/pessimistic.rb +9 -5
  146. data/lib/active_record/log_subscriber.rb +35 -35
  147. data/lib/active_record/middleware/database_selector.rb +77 -0
  148. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  149. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  150. data/lib/active_record/migration.rb +206 -157
  151. data/lib/active_record/migration/command_recorder.rb +96 -44
  152. data/lib/active_record/migration/compatibility.rb +142 -64
  153. data/lib/active_record/migration/join_table.rb +0 -1
  154. data/lib/active_record/model_schema.rb +148 -22
  155. data/lib/active_record/nested_attributes.rb +4 -7
  156. data/lib/active_record/no_touching.rb +8 -1
  157. data/lib/active_record/null_relation.rb +0 -1
  158. data/lib/active_record/persistence.rb +267 -59
  159. data/lib/active_record/query_cache.rb +21 -4
  160. data/lib/active_record/querying.rb +40 -23
  161. data/lib/active_record/railtie.rb +115 -58
  162. data/lib/active_record/railties/console_sandbox.rb +2 -4
  163. data/lib/active_record/railties/controller_runtime.rb +30 -35
  164. data/lib/active_record/railties/databases.rake +408 -78
  165. data/lib/active_record/readonly_attributes.rb +4 -0
  166. data/lib/active_record/reflection.rb +109 -93
  167. data/lib/active_record/relation.rb +374 -104
  168. data/lib/active_record/relation/batches.rb +44 -35
  169. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  170. data/lib/active_record/relation/calculations.rb +153 -90
  171. data/lib/active_record/relation/delegation.rb +35 -50
  172. data/lib/active_record/relation/finder_methods.rb +64 -39
  173. data/lib/active_record/relation/from_clause.rb +5 -1
  174. data/lib/active_record/relation/merger.rb +32 -40
  175. data/lib/active_record/relation/predicate_builder.rb +62 -45
  176. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  177. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  179. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  180. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  181. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  182. data/lib/active_record/relation/query_attribute.rb +13 -8
  183. data/lib/active_record/relation/query_methods.rb +475 -186
  184. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  185. data/lib/active_record/relation/spawn_methods.rb +9 -9
  186. data/lib/active_record/relation/where_clause.rb +111 -61
  187. data/lib/active_record/result.rb +64 -38
  188. data/lib/active_record/runtime_registry.rb +2 -2
  189. data/lib/active_record/sanitization.rb +22 -41
  190. data/lib/active_record/schema.rb +2 -11
  191. data/lib/active_record/schema_dumper.rb +54 -9
  192. data/lib/active_record/schema_migration.rb +7 -9
  193. data/lib/active_record/scoping.rb +8 -9
  194. data/lib/active_record/scoping/default.rb +4 -6
  195. data/lib/active_record/scoping/named.rb +17 -24
  196. data/lib/active_record/secure_token.rb +16 -8
  197. data/lib/active_record/serialization.rb +5 -3
  198. data/lib/active_record/signed_id.rb +116 -0
  199. data/lib/active_record/statement_cache.rb +49 -6
  200. data/lib/active_record/store.rb +88 -9
  201. data/lib/active_record/suppressor.rb +2 -2
  202. data/lib/active_record/table_metadata.rb +42 -43
  203. data/lib/active_record/tasks/database_tasks.rb +277 -81
  204. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  205. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  206. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  207. data/lib/active_record/test_databases.rb +24 -0
  208. data/lib/active_record/test_fixtures.rb +246 -0
  209. data/lib/active_record/timestamp.rb +43 -32
  210. data/lib/active_record/touch_later.rb +23 -22
  211. data/lib/active_record/transactions.rb +62 -118
  212. data/lib/active_record/translation.rb +1 -1
  213. data/lib/active_record/type.rb +10 -5
  214. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  215. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  216. data/lib/active_record/type/serialized.rb +6 -3
  217. data/lib/active_record/type/time.rb +10 -0
  218. data/lib/active_record/type/type_map.rb +0 -1
  219. data/lib/active_record/type/unsigned_integer.rb +0 -1
  220. data/lib/active_record/type_caster/connection.rb +15 -15
  221. data/lib/active_record/type_caster/map.rb +8 -8
  222. data/lib/active_record/validations.rb +4 -3
  223. data/lib/active_record/validations/associated.rb +1 -2
  224. data/lib/active_record/validations/numericality.rb +35 -0
  225. data/lib/active_record/validations/uniqueness.rb +38 -30
  226. data/lib/arel.rb +54 -0
  227. data/lib/arel/alias_predication.rb +9 -0
  228. data/lib/arel/attributes/attribute.rb +41 -0
  229. data/lib/arel/collectors/bind.rb +29 -0
  230. data/lib/arel/collectors/composite.rb +39 -0
  231. data/lib/arel/collectors/plain_string.rb +20 -0
  232. data/lib/arel/collectors/sql_string.rb +27 -0
  233. data/lib/arel/collectors/substitute_binds.rb +35 -0
  234. data/lib/arel/crud.rb +42 -0
  235. data/lib/arel/delete_manager.rb +18 -0
  236. data/lib/arel/errors.rb +9 -0
  237. data/lib/arel/expressions.rb +29 -0
  238. data/lib/arel/factory_methods.rb +49 -0
  239. data/lib/arel/insert_manager.rb +49 -0
  240. data/lib/arel/math.rb +45 -0
  241. data/lib/arel/nodes.rb +70 -0
  242. data/lib/arel/nodes/and.rb +32 -0
  243. data/lib/arel/nodes/ascending.rb +23 -0
  244. data/lib/arel/nodes/binary.rb +126 -0
  245. data/lib/arel/nodes/bind_param.rb +44 -0
  246. data/lib/arel/nodes/case.rb +55 -0
  247. data/lib/arel/nodes/casted.rb +62 -0
  248. data/lib/arel/nodes/comment.rb +29 -0
  249. data/lib/arel/nodes/count.rb +12 -0
  250. data/lib/arel/nodes/delete_statement.rb +45 -0
  251. data/lib/arel/nodes/descending.rb +23 -0
  252. data/lib/arel/nodes/equality.rb +15 -0
  253. data/lib/arel/nodes/extract.rb +24 -0
  254. data/lib/arel/nodes/false.rb +16 -0
  255. data/lib/arel/nodes/full_outer_join.rb +8 -0
  256. data/lib/arel/nodes/function.rb +44 -0
  257. data/lib/arel/nodes/grouping.rb +11 -0
  258. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  259. data/lib/arel/nodes/in.rb +15 -0
  260. data/lib/arel/nodes/infix_operation.rb +92 -0
  261. data/lib/arel/nodes/inner_join.rb +8 -0
  262. data/lib/arel/nodes/insert_statement.rb +37 -0
  263. data/lib/arel/nodes/join_source.rb +20 -0
  264. data/lib/arel/nodes/matches.rb +18 -0
  265. data/lib/arel/nodes/named_function.rb +23 -0
  266. data/lib/arel/nodes/node.rb +51 -0
  267. data/lib/arel/nodes/node_expression.rb +13 -0
  268. data/lib/arel/nodes/ordering.rb +27 -0
  269. data/lib/arel/nodes/outer_join.rb +8 -0
  270. data/lib/arel/nodes/over.rb +15 -0
  271. data/lib/arel/nodes/regexp.rb +16 -0
  272. data/lib/arel/nodes/right_outer_join.rb +8 -0
  273. data/lib/arel/nodes/select_core.rb +67 -0
  274. data/lib/arel/nodes/select_statement.rb +41 -0
  275. data/lib/arel/nodes/sql_literal.rb +19 -0
  276. data/lib/arel/nodes/string_join.rb +11 -0
  277. data/lib/arel/nodes/table_alias.rb +31 -0
  278. data/lib/arel/nodes/terminal.rb +16 -0
  279. data/lib/arel/nodes/true.rb +16 -0
  280. data/lib/arel/nodes/unary.rb +44 -0
  281. data/lib/arel/nodes/unary_operation.rb +20 -0
  282. data/lib/arel/nodes/unqualified_column.rb +22 -0
  283. data/lib/arel/nodes/update_statement.rb +41 -0
  284. data/lib/arel/nodes/values_list.rb +9 -0
  285. data/lib/arel/nodes/window.rb +126 -0
  286. data/lib/arel/nodes/with.rb +11 -0
  287. data/lib/arel/order_predications.rb +13 -0
  288. data/lib/arel/predications.rb +250 -0
  289. data/lib/arel/select_manager.rb +270 -0
  290. data/lib/arel/table.rb +118 -0
  291. data/lib/arel/tree_manager.rb +72 -0
  292. data/lib/arel/update_manager.rb +34 -0
  293. data/lib/arel/visitors.rb +13 -0
  294. data/lib/arel/visitors/dot.rb +308 -0
  295. data/lib/arel/visitors/mysql.rb +93 -0
  296. data/lib/arel/visitors/postgresql.rb +120 -0
  297. data/lib/arel/visitors/sqlite.rb +38 -0
  298. data/lib/arel/visitors/to_sql.rb +899 -0
  299. data/lib/arel/visitors/visitor.rb +45 -0
  300. data/lib/arel/window_predications.rb +9 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration.rb +19 -2
  303. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  304. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  305. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +119 -34
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -4,7 +4,6 @@ module ActiveRecord
4
4
  class Migration
5
5
  module JoinTable #:nodoc:
6
6
  private
7
-
8
7
  def find_join_table_name(table_1, table_2, options = {})
9
8
  options.delete(:table_name) || join_table_name(table_1, table_2)
10
9
  end
@@ -102,6 +102,30 @@ module ActiveRecord
102
102
  # If true, the default table name for a Product class will be "products". If false, it would just be "product".
103
103
  # See table_name for the full rules on table/class naming. This is true, by default.
104
104
 
105
+ ##
106
+ # :singleton-method: implicit_order_column
107
+ # :call-seq: implicit_order_column
108
+ #
109
+ # The name of the column records are ordered by if no explicit order clause
110
+ # is used during an ordered finder call. If not set the primary key is used.
111
+
112
+ ##
113
+ # :singleton-method: implicit_order_column=
114
+ # :call-seq: implicit_order_column=(column_name)
115
+ #
116
+ # Sets the column to sort records by when no explicit order clause is used
117
+ # during an ordered finder call. Useful when the primary key is not an
118
+ # auto-incrementing integer, for example when it's a UUID. Records are subsorted
119
+ # by the primary key if it exists to ensure deterministic results.
120
+
121
+ ##
122
+ # :singleton-method: immutable_strings_by_default=
123
+ # :call-seq: immutable_strings_by_default=(bool)
124
+ #
125
+ # Determines whether columns should infer their type as +:string+ or
126
+ # +:immutable_string+. This setting does not affect the behavior of
127
+ # <tt>attribute :foo, :string</tt>. Defaults to false.
128
+
105
129
  included do
106
130
  mattr_accessor :primary_key_prefix_type, instance_writer: false
107
131
 
@@ -110,12 +134,14 @@ module ActiveRecord
110
134
  class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
111
135
  class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
112
136
  class_attribute :pluralize_table_names, instance_writer: false, default: true
137
+ class_attribute :implicit_order_column, instance_accessor: false
138
+ class_attribute :immutable_strings_by_default, instance_accessor: false
113
139
 
114
140
  self.protected_environments = ["production"]
115
141
  self.inheritance_column = "type"
116
142
  self.ignored_columns = [].freeze
117
143
 
118
- delegate :type_for_attribute, to: :class
144
+ delegate :type_for_attribute, :column_for_attribute, to: :class
119
145
 
120
146
  initialize_load_schema_monitor
121
147
  end
@@ -218,11 +244,11 @@ module ActiveRecord
218
244
  end
219
245
 
220
246
  def full_table_name_prefix #:nodoc:
221
- (parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
247
+ (module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
222
248
  end
223
249
 
224
250
  def full_table_name_suffix #:nodoc:
225
- (parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
251
+ (module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
226
252
  end
227
253
 
228
254
  # The array of names of environments where destructive actions should be prohibited. By default,
@@ -271,12 +297,42 @@ module ActiveRecord
271
297
 
272
298
  # Sets the columns names the model should ignore. Ignored columns won't have attribute
273
299
  # accessors defined, and won't be referenced in SQL queries.
300
+ #
301
+ # A common usage pattern for this method is to ensure all references to an attribute
302
+ # have been removed and deployed, before a migration to drop the column from the database
303
+ # has been deployed and run. Using this two step approach to dropping columns ensures there
304
+ # is no code that raises errors due to having a cached schema in memory at the time the
305
+ # schema migration is run.
306
+ #
307
+ # For example, given a model where you want to drop the "category" attribute, first mark it
308
+ # as ignored:
309
+ #
310
+ # class Project < ActiveRecord::Base
311
+ # # schema:
312
+ # # id :bigint
313
+ # # name :string, limit: 255
314
+ # # category :string, limit: 255
315
+ #
316
+ # self.ignored_columns = [:category]
317
+ # end
318
+ #
319
+ # The schema still contains "category", but now the model omits it, so any meta-driven code or
320
+ # schema caching will not attempt to use the column:
321
+ #
322
+ # Project.columns_hash["category"] => nil
323
+ #
324
+ # You will get an error if accessing that attribute directly, so ensure all usages of the
325
+ # column are removed (automated tests can help you find any usages).
326
+ #
327
+ # user = Project.create!(name: "First Project")
328
+ # user.category # => raises NoMethodError
274
329
  def ignored_columns=(columns)
275
- @ignored_columns = columns.map(&:to_s)
330
+ reload_schema_from_cache
331
+ @ignored_columns = columns.map(&:to_s).freeze
276
332
  end
277
333
 
278
334
  def sequence_name
279
- if base_class == self
335
+ if base_class?
280
336
  @sequence_name ||= reset_sequence_name
281
337
  else
282
338
  (@sequence_name ||= nil) || base_class.sequence_name
@@ -339,7 +395,7 @@ module ActiveRecord
339
395
 
340
396
  def columns
341
397
  load_schema
342
- @columns ||= columns_hash.values
398
+ @columns ||= columns_hash.values.freeze
343
399
  end
344
400
 
345
401
  def attribute_types # :nodoc:
@@ -364,6 +420,8 @@ module ActiveRecord
364
420
  # a string or a symbol.
365
421
  def type_for_attribute(attr_name, &block)
366
422
  attr_name = attr_name.to_s
423
+ attr_name = attribute_aliases[attr_name] || attr_name
424
+
367
425
  if block
368
426
  attribute_types.fetch(attr_name, &block)
369
427
  else
@@ -371,11 +429,31 @@ module ActiveRecord
371
429
  end
372
430
  end
373
431
 
432
+ # Returns the column object for the named attribute.
433
+ # Returns an +ActiveRecord::ConnectionAdapters::NullColumn+ if the
434
+ # named attribute does not exist.
435
+ #
436
+ # class Person < ActiveRecord::Base
437
+ # end
438
+ #
439
+ # person = Person.new
440
+ # person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
441
+ # # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
442
+ #
443
+ # person.column_for_attribute(:nothing)
444
+ # # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
445
+ def column_for_attribute(name)
446
+ name = name.to_s
447
+ columns_hash.fetch(name) do
448
+ ConnectionAdapters::NullColumn.new(name)
449
+ end
450
+ end
451
+
374
452
  # Returns a hash where the keys are column names and the values are
375
453
  # default values when instantiating the Active Record object for this table.
376
454
  def column_defaults
377
455
  load_schema
378
- @column_defaults ||= _default_attributes.deep_dup.to_hash
456
+ @column_defaults ||= _default_attributes.deep_dup.to_hash.freeze
379
457
  end
380
458
 
381
459
  def _default_attributes # :nodoc:
@@ -385,7 +463,12 @@ module ActiveRecord
385
463
 
386
464
  # Returns an array of column names as strings.
387
465
  def column_names
388
- @column_names ||= columns.map(&:name)
466
+ @column_names ||= columns.map(&:name).freeze
467
+ end
468
+
469
+ def symbol_column_to_string(name_symbol) # :nodoc:
470
+ @symbol_column_to_string_name_hash ||= column_names.index_by(&:to_sym)
471
+ @symbol_column_to_string_name_hash[name_symbol]
389
472
  end
390
473
 
391
474
  # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
@@ -394,9 +477,8 @@ module ActiveRecord
394
477
  @content_columns ||= columns.reject do |c|
395
478
  c.name == primary_key ||
396
479
  c.name == inheritance_column ||
397
- c.name.end_with?("_id") ||
398
- c.name.end_with?("_count")
399
- end
480
+ c.name.end_with?("_id", "_count")
481
+ end.freeze
400
482
  end
401
483
 
402
484
  # Resets all the cached information about columns, which will cause them
@@ -406,7 +488,7 @@ module ActiveRecord
406
488
  # when just after creating a table you want to populate it with some default
407
489
  # values, eg:
408
490
  #
409
- # class CreateJobLevels < ActiveRecord::Migration[5.0]
491
+ # class CreateJobLevels < ActiveRecord::Migration[6.0]
410
492
  # def up
411
493
  # create_table :job_levels do |t|
412
494
  # t.integer :id
@@ -435,13 +517,11 @@ module ActiveRecord
435
517
  end
436
518
 
437
519
  protected
438
-
439
520
  def initialize_load_schema_monitor
440
521
  @load_schema_monitor = Monitor.new
441
522
  end
442
523
 
443
524
  private
444
-
445
525
  def inherited(child_class)
446
526
  super
447
527
  child_class.initialize_load_schema_monitor
@@ -459,15 +539,27 @@ module ActiveRecord
459
539
  load_schema!
460
540
 
461
541
  @schema_loaded = true
542
+ rescue
543
+ reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
544
+ raise
462
545
  end
463
546
  end
464
547
 
465
548
  def load_schema!
466
- @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
549
+ unless table_name
550
+ raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
551
+ end
552
+
553
+ columns_hash = connection.schema_cache.columns_hash(table_name)
554
+ columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
555
+ @columns_hash = columns_hash.freeze
467
556
  @columns_hash.each do |name, column|
557
+ type = connection.lookup_cast_type_from_column(column)
558
+ type = _convert_type_from_options(type)
559
+ warn_if_deprecated_type(column)
468
560
  define_attribute(
469
561
  name,
470
- connection.lookup_cast_type_from_column(column),
562
+ type,
471
563
  default: column.default,
472
564
  user_provided_default: false
473
565
  )
@@ -477,6 +569,7 @@ module ActiveRecord
477
569
  def reload_schema_from_cache
478
570
  @arel_table = nil
479
571
  @column_names = nil
572
+ @symbol_column_to_string_name_hash = nil
480
573
  @attribute_types = nil
481
574
  @content_columns = nil
482
575
  @default_attributes = nil
@@ -501,19 +594,52 @@ module ActiveRecord
501
594
 
502
595
  # Computes and returns a table name according to default conventions.
503
596
  def compute_table_name
504
- base = base_class
505
- if self == base
597
+ if base_class?
506
598
  # Nested classes are prefixed with singular parent table name.
507
- if parent < Base && !parent.abstract_class?
508
- contained = parent.table_name
509
- contained = contained.singularize if parent.pluralize_table_names
599
+ if module_parent < Base && !module_parent.abstract_class?
600
+ contained = module_parent.table_name
601
+ contained = contained.singularize if module_parent.pluralize_table_names
510
602
  contained += "_"
511
603
  end
512
604
 
513
605
  "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
514
606
  else
515
607
  # STI subclasses always use their superclass' table.
516
- base.table_name
608
+ base_class.table_name
609
+ end
610
+ end
611
+
612
+ def _convert_type_from_options(type)
613
+ if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
614
+ type.to_immutable_string
615
+ else
616
+ type
617
+ end
618
+ end
619
+
620
+ def warn_if_deprecated_type(column)
621
+ return if attributes_to_define_after_schema_loads.key?(column.name)
622
+ return unless column.respond_to?(:oid)
623
+
624
+ if column.array?
625
+ array_arguments = ", array: true"
626
+ else
627
+ array_arguments = ""
628
+ end
629
+
630
+ if column.sql_type.start_with?("interval")
631
+ precision_arguments = column.precision.presence && ", precision: #{column.precision}"
632
+ ActiveSupport::Deprecation.warn(<<~WARNING)
633
+ The behavior of the `:interval` type will be changing in Rails 6.2
634
+ to return an `ActiveSupport::Duration` object. If you'd like to keep
635
+ the old behavior, you can add this line to #{self.name} model:
636
+
637
+ attribute :#{column.name}, :string#{precision_arguments}#{array_arguments}
638
+
639
+ If you'd like the new behavior today, you can add this line:
640
+
641
+ attribute :#{column.name}, :interval#{precision_arguments}#{array_arguments}
642
+ WARNING
517
643
  end
518
644
  end
519
645
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "active_support/core_ext/hash/except"
4
4
  require "active_support/core_ext/module/redefine_method"
5
- require "active_support/core_ext/object/try"
6
5
  require "active_support/core_ext/hash/indifferent_access"
7
6
 
8
7
  module ActiveRecord
@@ -289,7 +288,7 @@ module ActiveRecord
289
288
  # [:allow_destroy]
290
289
  # If true, destroys any members from the attributes hash with a
291
290
  # <tt>_destroy</tt> key and a value that evaluates to +true+
292
- # (eg. 1, '1', true, or 'true'). This option is off by default.
291
+ # (e.g. 1, '1', true, or 'true'). This option is off by default.
293
292
  # [:reject_if]
294
293
  # Allows you to specify a Proc or a Symbol pointing to a method
295
294
  # that checks whether a record should be built for a certain attribute
@@ -354,7 +353,6 @@ module ActiveRecord
354
353
  end
355
354
 
356
355
  private
357
-
358
356
  # Generates a writer method for this association. Serves as a point for
359
357
  # accessing the objects in the association. For example, this method
360
358
  # could generate the following:
@@ -386,7 +384,6 @@ module ActiveRecord
386
384
  end
387
385
 
388
386
  private
389
-
390
387
  # Attribute hash keys that should not be assigned as normal attributes.
391
388
  # These hash keys are nested attributes implementation details.
392
389
  UNASSIGNABLE_KEYS = %w( id _destroy )
@@ -426,7 +423,7 @@ module ActiveRecord
426
423
  existing_record.assign_attributes(assignable_attributes)
427
424
  association(association_name).initialize_attributes(existing_record)
428
425
  else
429
- method = "build_#{association_name}"
426
+ method = :"build_#{association_name}"
430
427
  if respond_to?(method)
431
428
  send(method, assignable_attributes)
432
429
  else
@@ -501,7 +498,7 @@ module ActiveRecord
501
498
 
502
499
  if attributes["id"].blank?
503
500
  unless reject_new_record?(association_name, attributes)
504
- association.build(attributes.except(*UNASSIGNABLE_KEYS))
501
+ association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
505
502
  end
506
503
  elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
507
504
  unless call_reject_if(association_name, attributes)
@@ -512,7 +509,7 @@ module ActiveRecord
512
509
  if target_record
513
510
  existing_record = target_record
514
511
  else
515
- association.add_to_target(existing_record, :skip_callbacks)
512
+ association.add_to_target(existing_record, skip_callbacks: true)
516
513
  end
517
514
 
518
515
  assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
@@ -43,6 +43,13 @@ module ActiveRecord
43
43
  end
44
44
  end
45
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
+ #
46
53
  def no_touching?
47
54
  NoTouching.applied_to?(self.class)
48
55
  end
@@ -51,7 +58,7 @@ module ActiveRecord
51
58
  super unless no_touching?
52
59
  end
53
60
 
54
- def touch(*) # :nodoc:
61
+ def touch(*, **) # :nodoc:
55
62
  super unless no_touching?
56
63
  end
57
64
  end
@@ -60,7 +60,6 @@ module ActiveRecord
60
60
  end
61
61
 
62
62
  private
63
-
64
63
  def exec_queries
65
64
  @records = [].freeze
66
65
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_record/insert_all"
4
+
3
5
  module ActiveRecord
4
6
  # = Active Record \Persistence
5
7
  module Persistence
@@ -55,6 +57,192 @@ module ActiveRecord
55
57
  end
56
58
  end
57
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
+
58
246
  # Given an attributes hash, +instantiate+ returns a new instance of
59
247
  # the appropriate class. Accepts only keys as strings.
60
248
  #
@@ -67,8 +255,7 @@ module ActiveRecord
67
255
  # how this "single-table" inheritance mapping is implemented.
68
256
  def instantiate(attributes, column_types = {}, &block)
69
257
  klass = discriminate_class_for_record(attributes)
70
- attributes = klass.attributes_builder.build_from_database(attributes, column_types)
71
- klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
258
+ instantiate_instance_of(klass, attributes, column_types, &block)
72
259
  end
73
260
 
74
261
  # Updates an object (or multiple objects) and saves it to the database, if validations pass.
@@ -143,7 +330,7 @@ module ActiveRecord
143
330
  end
144
331
  end
145
332
 
146
- # Deletes the row with a primary key matching the +id+ argument, using a
333
+ # Deletes the row with a primary key matching the +id+ argument, using an
147
334
  # SQL +DELETE+ statement, and returns the number of rows deleted. Active
148
335
  # Record objects are not instantiated, so the object's callbacks are not
149
336
  # executed, including any <tt>:dependent</tt> association options.
@@ -162,10 +349,11 @@ module ActiveRecord
162
349
  # # Delete multiple rows
163
350
  # Todo.delete([2,3,4])
164
351
  def delete(id_or_array)
165
- where(primary_key => id_or_array).delete_all
352
+ delete_by(primary_key => id_or_array)
166
353
  end
167
354
 
168
355
  def _insert_record(values) # :nodoc:
356
+ primary_key = self.primary_key
169
357
  primary_key_value = nil
170
358
 
171
359
  if primary_key && Hash === values
@@ -178,7 +366,7 @@ module ActiveRecord
178
366
  end
179
367
 
180
368
  if values.empty?
181
- im = arel_table.compile_insert(connection.empty_insert_statement_value)
369
+ im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
182
370
  im.into arel_table
183
371
  else
184
372
  im = arel_table.compile_insert(_substitute_values(values))
@@ -208,6 +396,13 @@ module ActiveRecord
208
396
  end
209
397
 
210
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
+
211
406
  # Called by +instantiate+ to decide which class to use for a new
212
407
  # record instance.
213
408
  #
@@ -219,8 +414,8 @@ module ActiveRecord
219
414
 
220
415
  def _substitute_values(values)
221
416
  values.map do |name, value|
222
- attr = arel_attribute(name)
223
- bind = predicate_builder.build_bind_attribute(name, value)
417
+ attr = arel_table[name]
418
+ bind = predicate_builder.build_bind_attribute(attr.name, value)
224
419
  [attr, bind]
225
420
  end
226
421
  end
@@ -229,26 +424,30 @@ module ActiveRecord
229
424
  # Returns true if this object hasn't been saved yet -- that is, a record
230
425
  # for the object doesn't exist in the database yet; otherwise, returns false.
231
426
  def new_record?
232
- sync_with_transaction_state
233
427
  @new_record
234
428
  end
235
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
+
236
437
  # Returns true if this object has been destroyed, otherwise returns false.
237
438
  def destroyed?
238
- sync_with_transaction_state
239
439
  @destroyed
240
440
  end
241
441
 
242
442
  # Returns true if the record is persisted, i.e. it's not a new record and it was
243
443
  # not destroyed, otherwise returns false.
244
444
  def persisted?
245
- sync_with_transaction_state
246
445
  !(@new_record || @destroyed)
247
446
  end
248
447
 
249
448
  ##
250
449
  # :call-seq:
251
- # save(*args)
450
+ # save(**options)
252
451
  #
253
452
  # Saves the model.
254
453
  #
@@ -271,15 +470,15 @@ module ActiveRecord
271
470
  #
272
471
  # Attributes marked as readonly are silently ignored if the record is
273
472
  # being updated.
274
- def save(*args, &block)
275
- create_or_update(*args, &block)
473
+ def save(**options, &block)
474
+ create_or_update(**options, &block)
276
475
  rescue ActiveRecord::RecordInvalid
277
476
  false
278
477
  end
279
478
 
280
479
  ##
281
480
  # :call-seq:
282
- # save!(*args)
481
+ # save!(**options)
283
482
  #
284
483
  # Saves the model.
285
484
  #
@@ -304,8 +503,8 @@ module ActiveRecord
304
503
  # being updated.
305
504
  #
306
505
  # Unless an error is raised, returns true.
307
- def save!(*args, &block)
308
- create_or_update(*args, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
506
+ def save!(**options, &block)
507
+ create_or_update(**options, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
309
508
  end
310
509
 
311
510
  # Deletes the record in the database and freezes this instance to
@@ -319,7 +518,7 @@ module ActiveRecord
319
518
  #
320
519
  # To enforce the object's +before_destroy+ and +after_destroy+
321
520
  # callbacks or any <tt>:dependent</tt> association
322
- # options, use <tt>#destroy</tt>.
521
+ # options, use #destroy.
323
522
  def delete
324
523
  _delete_row if persisted?
325
524
  @destroyed = true
@@ -336,7 +535,6 @@ module ActiveRecord
336
535
  def destroy
337
536
  _raise_readonly_record_error if readonly?
338
537
  destroy_associations
339
- self.class.connection.add_transaction_record(self)
340
538
  @_trigger_destroy_callback = if persisted?
341
539
  destroy_row > 0
342
540
  else
@@ -371,13 +569,15 @@ module ActiveRecord
371
569
  # If you want to change the sti column as well, use #becomes! instead.
372
570
  def becomes(klass)
373
571
  became = klass.allocate
374
- became.send(:initialize)
375
- became.instance_variable_set("@attributes", @attributes)
376
- became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
377
- became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
378
- became.instance_variable_set("@new_record", new_record?)
379
- became.instance_variable_set("@destroyed", destroyed?)
380
- became.errors.copy!(errors)
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
+
381
581
  became
382
582
  end
383
583
 
@@ -429,8 +629,6 @@ module ActiveRecord
429
629
  end
430
630
  end
431
631
 
432
- alias update_attributes update
433
-
434
632
  # Updates its receiver just like #update but calls #save! instead
435
633
  # of +save+, so an exception is raised if the record is invalid and saving will fail.
436
634
  def update!(attributes)
@@ -442,8 +640,6 @@ module ActiveRecord
442
640
  end
443
641
  end
444
642
 
445
- alias update_attributes! update!
446
-
447
643
  # Equivalent to <code>update_columns(name => value)</code>.
448
644
  def update_column(name, value)
449
645
  update_columns(name => value)
@@ -469,8 +665,10 @@ module ActiveRecord
469
665
  raise ActiveRecordError, "cannot update a new record" if new_record?
470
666
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
471
667
 
472
- attributes.each_key do |key|
473
- 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
474
672
  end
475
673
 
476
674
  id_in_database = self.id_in_database
@@ -480,7 +678,7 @@ module ActiveRecord
480
678
 
481
679
  affected_rows = self.class._update_record(
482
680
  attributes,
483
- self.class.primary_key => id_in_database
681
+ @primary_key => id_in_database
484
682
  )
485
683
 
486
684
  affected_rows == 1
@@ -503,9 +701,9 @@ module ActiveRecord
503
701
  # Returns +self+.
504
702
  def increment!(attribute, by = 1, touch: nil)
505
703
  increment(attribute, by)
506
- change = public_send(attribute) - (attribute_in_database(attribute.to_s) || 0)
704
+ change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0)
507
705
  self.class.update_counters(id, attribute => change, touch: touch)
508
- clear_attribute_change(attribute) # eww
706
+ public_send(:"clear_#{attribute}_change")
509
707
  self
510
708
  end
511
709
 
@@ -609,8 +807,9 @@ module ActiveRecord
609
807
  self.class.unscoped { self.class.find(id) }
610
808
  end
611
809
 
612
- @attributes = fresh_object.instance_variable_get("@attributes")
810
+ @attributes = fresh_object.instance_variable_get(:@attributes)
613
811
  @new_record = false
812
+ @previously_new_record = false
614
813
  self
615
814
  end
616
815
 
@@ -649,15 +848,13 @@ module ActiveRecord
649
848
  # ball.touch(:updated_at) # => raises ActiveRecordError
650
849
  #
651
850
  def touch(*names, time: nil)
652
- unless persisted?
653
- raise ActiveRecordError, <<-MSG.squish
654
- cannot touch on a new or destroyed record object. Consider using
655
- persisted?, new_record?, or destroyed? before touching
656
- MSG
657
- end
851
+ _raise_record_not_touched_error unless persisted?
658
852
 
659
853
  attribute_names = timestamp_attributes_for_update_in_model
660
- attribute_names |= names.map(&:to_s)
854
+ attribute_names |= names.map! do |name|
855
+ name = name.to_s
856
+ self.class.attribute_aliases[name] || name
857
+ end unless names.empty?
661
858
 
662
859
  unless attribute_names.empty?
663
860
  affected_rows = _touch_row(attribute_names, time)
@@ -668,7 +865,6 @@ module ActiveRecord
668
865
  end
669
866
 
670
867
  private
671
-
672
868
  # A hook to be overridden by association modules.
673
869
  def destroy_associations
674
870
  end
@@ -678,15 +874,14 @@ module ActiveRecord
678
874
  end
679
875
 
680
876
  def _delete_row
681
- self.class._delete_record(self.class.primary_key => id_in_database)
877
+ self.class._delete_record(@primary_key => id_in_database)
682
878
  end
683
879
 
684
880
  def _touch_row(attribute_names, time)
685
881
  time ||= current_time_from_proper_timezone
686
882
 
687
883
  attribute_names.each do |attr_name|
688
- write_attribute(attr_name, time)
689
- clear_attribute_change(attr_name)
884
+ _write_attribute(attr_name, time)
690
885
  end
691
886
 
692
887
  _update_row(attribute_names, "touch")
@@ -695,21 +890,20 @@ module ActiveRecord
695
890
  def _update_row(attribute_names, attempted_action = "update")
696
891
  self.class._update_record(
697
892
  attributes_with_values(attribute_names),
698
- self.class.primary_key => id_in_database
893
+ @primary_key => id_in_database
699
894
  )
700
895
  end
701
896
 
702
- def create_or_update(*args, &block)
897
+ def create_or_update(**, &block)
703
898
  _raise_readonly_record_error if readonly?
704
899
  return false if destroyed?
705
- result = new_record? ? _create_record(&block) : _update_record(*args, &block)
900
+ result = new_record? ? _create_record(&block) : _update_record(&block)
706
901
  result != false
707
902
  end
708
903
 
709
904
  # Updates the associated record with values matching those of the instance attributes.
710
905
  # Returns the number of affected rows.
711
906
  def _update_record(attribute_names = self.attribute_names)
712
- attribute_names &= self.class.column_names
713
907
  attribute_names = attributes_for_update(attribute_names)
714
908
 
715
909
  if attribute_names.empty?
@@ -720,6 +914,8 @@ module ActiveRecord
720
914
  @_trigger_update_callback = affected_rows == 1
721
915
  end
722
916
 
917
+ @previously_new_record = false
918
+
723
919
  yield(self) if block_given?
724
920
 
725
921
  affected_rows
@@ -728,13 +924,16 @@ module ActiveRecord
728
924
  # Creates a record with values matching those of the instance attributes
729
925
  # and returns its id.
730
926
  def _create_record(attribute_names = self.attribute_names)
731
- attribute_names &= self.class.column_names
732
- attributes_values = attributes_with_values_for_create(attribute_names)
927
+ attribute_names = attributes_for_create(attribute_names)
733
928
 
734
- new_id = self.class._insert_record(attributes_values)
735
- self.id ||= new_id if self.class.primary_key
929
+ new_id = self.class._insert_record(
930
+ attributes_with_values(attribute_names)
931
+ )
932
+
933
+ self.id ||= new_id if @primary_key
736
934
 
737
935
  @new_record = false
936
+ @previously_new_record = true
738
937
 
739
938
  yield(self) if block_given?
740
939
 
@@ -742,7 +941,7 @@ module ActiveRecord
742
941
  end
743
942
 
744
943
  def verify_readonly_attribute(name)
745
- 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)
746
945
  end
747
946
 
748
947
  def _raise_record_not_destroyed
@@ -752,12 +951,21 @@ module ActiveRecord
752
951
  @_association_destroy_exception = nil
753
952
  end
754
953
 
755
- def belongs_to_touch_method
756
- :touch
757
- end
758
-
759
954
  def _raise_readonly_record_error
760
955
  raise ReadOnlyRecord, "#{self.class} is marked as readonly"
761
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.
967
+ def belongs_to_touch_method
968
+ :touch
969
+ end
762
970
  end
763
971
  end