activerecord 5.2.2.1 → 6.0.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 (269) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +734 -508
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +4 -2
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +9 -2
  7. data/lib/active_record/aggregations.rb +4 -2
  8. data/lib/active_record/association_relation.rb +15 -6
  9. data/lib/active_record/associations.rb +20 -15
  10. data/lib/active_record/associations/association.rb +61 -20
  11. data/lib/active_record/associations/association_scope.rb +4 -6
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +16 -28
  22. data/lib/active_record/associations/collection_proxy.rb +19 -48
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +3 -10
  25. data/lib/active_record/associations/has_many_through_association.rb +20 -25
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency.rb +28 -28
  29. data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +40 -32
  32. data/lib/active_record/associations/preloader/association.rb +38 -36
  33. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/attribute_assignment.rb +7 -10
  36. data/lib/active_record/attribute_methods.rb +28 -100
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  38. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  40. data/lib/active_record/attribute_methods/query.rb +2 -3
  41. data/lib/active_record/attribute_methods/read.rb +15 -53
  42. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  44. data/lib/active_record/attribute_methods/write.rb +17 -24
  45. data/lib/active_record/attributes.rb +13 -0
  46. data/lib/active_record/autosave_association.rb +22 -8
  47. data/lib/active_record/base.rb +2 -3
  48. data/lib/active_record/callbacks.rb +5 -19
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +137 -26
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +114 -130
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +26 -11
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +135 -56
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +189 -43
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +151 -198
  61. data/lib/active_record/connection_adapters/column.rb +17 -13
  62. data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
  63. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +7 -11
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  66. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  67. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  68. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  69. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  70. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  71. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
  72. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  75. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  76. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  81. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  82. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  83. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  84. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +47 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  86. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -77
  87. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  88. data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
  89. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  90. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  91. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  92. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -5
  93. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  94. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +131 -143
  95. data/lib/active_record/connection_handling.rb +155 -26
  96. data/lib/active_record/core.rb +104 -59
  97. data/lib/active_record/counter_cache.rb +4 -29
  98. data/lib/active_record/database_configurations.rb +233 -0
  99. data/lib/active_record/database_configurations/database_config.rb +37 -0
  100. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  101. data/lib/active_record/database_configurations/url_config.rb +79 -0
  102. data/lib/active_record/dynamic_matchers.rb +1 -1
  103. data/lib/active_record/enum.rb +37 -7
  104. data/lib/active_record/errors.rb +30 -16
  105. data/lib/active_record/explain.rb +1 -1
  106. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  107. data/lib/active_record/fixture_set/render_context.rb +17 -0
  108. data/lib/active_record/fixture_set/table_row.rb +153 -0
  109. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  110. data/lib/active_record/fixtures.rb +145 -472
  111. data/lib/active_record/gem_version.rb +3 -3
  112. data/lib/active_record/inheritance.rb +13 -3
  113. data/lib/active_record/insert_all.rb +179 -0
  114. data/lib/active_record/integration.rb +68 -16
  115. data/lib/active_record/internal_metadata.rb +10 -2
  116. data/lib/active_record/locking/optimistic.rb +5 -6
  117. data/lib/active_record/locking/pessimistic.rb +3 -3
  118. data/lib/active_record/log_subscriber.rb +7 -26
  119. data/lib/active_record/middleware/database_selector.rb +75 -0
  120. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  121. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  122. data/lib/active_record/migration.rb +100 -81
  123. data/lib/active_record/migration/command_recorder.rb +50 -6
  124. data/lib/active_record/migration/compatibility.rb +91 -64
  125. data/lib/active_record/model_schema.rb +33 -9
  126. data/lib/active_record/nested_attributes.rb +2 -2
  127. data/lib/active_record/no_touching.rb +7 -0
  128. data/lib/active_record/persistence.rb +231 -25
  129. data/lib/active_record/query_cache.rb +11 -4
  130. data/lib/active_record/querying.rb +33 -22
  131. data/lib/active_record/railtie.rb +80 -43
  132. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  133. data/lib/active_record/railties/controller_runtime.rb +30 -35
  134. data/lib/active_record/railties/databases.rake +199 -46
  135. data/lib/active_record/reflection.rb +42 -44
  136. data/lib/active_record/relation.rb +311 -80
  137. data/lib/active_record/relation/batches.rb +13 -10
  138. data/lib/active_record/relation/calculations.rb +67 -57
  139. data/lib/active_record/relation/delegation.rb +26 -43
  140. data/lib/active_record/relation/finder_methods.rb +28 -28
  141. data/lib/active_record/relation/merger.rb +17 -23
  142. data/lib/active_record/relation/predicate_builder.rb +18 -15
  143. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  144. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  145. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  146. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  147. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  148. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  149. data/lib/active_record/relation/query_attribute.rb +17 -10
  150. data/lib/active_record/relation/query_methods.rb +247 -73
  151. data/lib/active_record/relation/spawn_methods.rb +1 -1
  152. data/lib/active_record/relation/where_clause.rb +14 -10
  153. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  154. data/lib/active_record/result.rb +30 -11
  155. data/lib/active_record/sanitization.rb +32 -40
  156. data/lib/active_record/schema.rb +2 -11
  157. data/lib/active_record/schema_dumper.rb +22 -7
  158. data/lib/active_record/schema_migration.rb +5 -1
  159. data/lib/active_record/scoping.rb +8 -8
  160. data/lib/active_record/scoping/default.rb +6 -7
  161. data/lib/active_record/scoping/named.rb +20 -15
  162. data/lib/active_record/statement_cache.rb +32 -5
  163. data/lib/active_record/store.rb +87 -8
  164. data/lib/active_record/table_metadata.rb +10 -17
  165. data/lib/active_record/tasks/database_tasks.rb +194 -25
  166. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  167. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  168. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  169. data/lib/active_record/test_databases.rb +23 -0
  170. data/lib/active_record/test_fixtures.rb +225 -0
  171. data/lib/active_record/timestamp.rb +39 -25
  172. data/lib/active_record/touch_later.rb +4 -2
  173. data/lib/active_record/transactions.rb +57 -66
  174. data/lib/active_record/translation.rb +1 -1
  175. data/lib/active_record/type.rb +3 -4
  176. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  177. data/lib/active_record/type_caster/connection.rb +15 -14
  178. data/lib/active_record/type_caster/map.rb +1 -4
  179. data/lib/active_record/validations.rb +1 -0
  180. data/lib/active_record/validations/uniqueness.rb +15 -27
  181. data/lib/arel.rb +58 -0
  182. data/lib/arel/alias_predication.rb +9 -0
  183. data/lib/arel/attributes.rb +22 -0
  184. data/lib/arel/attributes/attribute.rb +37 -0
  185. data/lib/arel/collectors/bind.rb +24 -0
  186. data/lib/arel/collectors/composite.rb +31 -0
  187. data/lib/arel/collectors/plain_string.rb +20 -0
  188. data/lib/arel/collectors/sql_string.rb +20 -0
  189. data/lib/arel/collectors/substitute_binds.rb +28 -0
  190. data/lib/arel/crud.rb +42 -0
  191. data/lib/arel/delete_manager.rb +18 -0
  192. data/lib/arel/errors.rb +9 -0
  193. data/lib/arel/expressions.rb +29 -0
  194. data/lib/arel/factory_methods.rb +49 -0
  195. data/lib/arel/insert_manager.rb +49 -0
  196. data/lib/arel/math.rb +45 -0
  197. data/lib/arel/nodes.rb +68 -0
  198. data/lib/arel/nodes/and.rb +32 -0
  199. data/lib/arel/nodes/ascending.rb +23 -0
  200. data/lib/arel/nodes/binary.rb +52 -0
  201. data/lib/arel/nodes/bind_param.rb +36 -0
  202. data/lib/arel/nodes/case.rb +55 -0
  203. data/lib/arel/nodes/casted.rb +50 -0
  204. data/lib/arel/nodes/comment.rb +29 -0
  205. data/lib/arel/nodes/count.rb +12 -0
  206. data/lib/arel/nodes/delete_statement.rb +45 -0
  207. data/lib/arel/nodes/descending.rb +23 -0
  208. data/lib/arel/nodes/equality.rb +18 -0
  209. data/lib/arel/nodes/extract.rb +24 -0
  210. data/lib/arel/nodes/false.rb +16 -0
  211. data/lib/arel/nodes/full_outer_join.rb +8 -0
  212. data/lib/arel/nodes/function.rb +44 -0
  213. data/lib/arel/nodes/grouping.rb +8 -0
  214. data/lib/arel/nodes/in.rb +8 -0
  215. data/lib/arel/nodes/infix_operation.rb +80 -0
  216. data/lib/arel/nodes/inner_join.rb +8 -0
  217. data/lib/arel/nodes/insert_statement.rb +37 -0
  218. data/lib/arel/nodes/join_source.rb +20 -0
  219. data/lib/arel/nodes/matches.rb +18 -0
  220. data/lib/arel/nodes/named_function.rb +23 -0
  221. data/lib/arel/nodes/node.rb +50 -0
  222. data/lib/arel/nodes/node_expression.rb +13 -0
  223. data/lib/arel/nodes/outer_join.rb +8 -0
  224. data/lib/arel/nodes/over.rb +15 -0
  225. data/lib/arel/nodes/regexp.rb +16 -0
  226. data/lib/arel/nodes/right_outer_join.rb +8 -0
  227. data/lib/arel/nodes/select_core.rb +67 -0
  228. data/lib/arel/nodes/select_statement.rb +41 -0
  229. data/lib/arel/nodes/sql_literal.rb +16 -0
  230. data/lib/arel/nodes/string_join.rb +11 -0
  231. data/lib/arel/nodes/table_alias.rb +27 -0
  232. data/lib/arel/nodes/terminal.rb +16 -0
  233. data/lib/arel/nodes/true.rb +16 -0
  234. data/lib/arel/nodes/unary.rb +45 -0
  235. data/lib/arel/nodes/unary_operation.rb +20 -0
  236. data/lib/arel/nodes/unqualified_column.rb +22 -0
  237. data/lib/arel/nodes/update_statement.rb +41 -0
  238. data/lib/arel/nodes/values_list.rb +9 -0
  239. data/lib/arel/nodes/window.rb +126 -0
  240. data/lib/arel/nodes/with.rb +11 -0
  241. data/lib/arel/order_predications.rb +13 -0
  242. data/lib/arel/predications.rb +257 -0
  243. data/lib/arel/select_manager.rb +271 -0
  244. data/lib/arel/table.rb +110 -0
  245. data/lib/arel/tree_manager.rb +72 -0
  246. data/lib/arel/update_manager.rb +34 -0
  247. data/lib/arel/visitors.rb +20 -0
  248. data/lib/arel/visitors/depth_first.rb +204 -0
  249. data/lib/arel/visitors/dot.rb +297 -0
  250. data/lib/arel/visitors/ibm_db.rb +34 -0
  251. data/lib/arel/visitors/informix.rb +62 -0
  252. data/lib/arel/visitors/mssql.rb +157 -0
  253. data/lib/arel/visitors/mysql.rb +83 -0
  254. data/lib/arel/visitors/oracle.rb +159 -0
  255. data/lib/arel/visitors/oracle12.rb +66 -0
  256. data/lib/arel/visitors/postgresql.rb +110 -0
  257. data/lib/arel/visitors/sqlite.rb +39 -0
  258. data/lib/arel/visitors/to_sql.rb +889 -0
  259. data/lib/arel/visitors/visitor.rb +46 -0
  260. data/lib/arel/visitors/where_sql.rb +23 -0
  261. data/lib/arel/window_predications.rb +9 -0
  262. data/lib/rails/generators/active_record/migration.rb +14 -1
  263. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  264. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  265. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  266. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  267. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  268. metadata +111 -26
  269. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -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
@@ -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.
@@ -97,11 +284,13 @@ module ActiveRecord
97
284
  # When running callbacks is not needed for each record update,
98
285
  # it is preferred to use {update_all}[rdoc-ref:Relation#update_all]
99
286
  # for updating all records in a single query.
100
- def update(id, attributes)
287
+ def update(id = :all, attributes)
101
288
  if id.is_a?(Array)
102
289
  id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
103
290
  object.update(attributes[idx])
104
291
  }
292
+ elsif id == :all
293
+ all.each { |record| record.update(attributes) }
105
294
  else
106
295
  if ActiveRecord::Base === id
107
296
  raise ArgumentError,
@@ -141,7 +330,7 @@ module ActiveRecord
141
330
  end
142
331
  end
143
332
 
144
- # 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
145
334
  # SQL +DELETE+ statement, and returns the number of rows deleted. Active
146
335
  # Record objects are not instantiated, so the object's callbacks are not
147
336
  # executed, including any <tt>:dependent</tt> association options.
@@ -160,10 +349,11 @@ module ActiveRecord
160
349
  # # Delete multiple rows
161
350
  # Todo.delete([2,3,4])
162
351
  def delete(id_or_array)
163
- where(primary_key => id_or_array).delete_all
352
+ delete_by(primary_key => id_or_array)
164
353
  end
165
354
 
166
355
  def _insert_record(values) # :nodoc:
356
+ primary_key = self.primary_key
167
357
  primary_key_value = nil
168
358
 
169
359
  if primary_key && Hash === values
@@ -176,7 +366,7 @@ module ActiveRecord
176
366
  end
177
367
 
178
368
  if values.empty?
179
- im = arel_table.compile_insert(connection.empty_insert_statement_value)
369
+ im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
180
370
  im.into arel_table
181
371
  else
182
372
  im = arel_table.compile_insert(_substitute_values(values))
@@ -206,6 +396,13 @@ module ActiveRecord
206
396
  end
207
397
 
208
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
+
209
406
  # Called by +instantiate+ to decide which class to use for a new
210
407
  # record instance.
211
408
  #
@@ -227,20 +424,20 @@ module ActiveRecord
227
424
  # Returns true if this object hasn't been saved yet -- that is, a record
228
425
  # for the object doesn't exist in the database yet; otherwise, returns false.
229
426
  def new_record?
230
- sync_with_transaction_state
427
+ sync_with_transaction_state if @transaction_state&.finalized?
231
428
  @new_record
232
429
  end
233
430
 
234
431
  # Returns true if this object has been destroyed, otherwise returns false.
235
432
  def destroyed?
236
- sync_with_transaction_state
433
+ sync_with_transaction_state if @transaction_state&.finalized?
237
434
  @destroyed
238
435
  end
239
436
 
240
437
  # Returns true if the record is persisted, i.e. it's not a new record and it was
241
438
  # not destroyed, otherwise returns false.
242
439
  def persisted?
243
- sync_with_transaction_state
440
+ sync_with_transaction_state if @transaction_state&.finalized?
244
441
  !(@new_record || @destroyed)
245
442
  end
246
443
 
@@ -334,7 +531,6 @@ module ActiveRecord
334
531
  def destroy
335
532
  _raise_readonly_record_error if readonly?
336
533
  destroy_associations
337
- self.class.connection.add_transaction_record(self)
338
534
  @_trigger_destroy_callback = if persisted?
339
535
  destroy_row > 0
340
536
  else
@@ -372,7 +568,6 @@ module ActiveRecord
372
568
  became.send(:initialize)
373
569
  became.instance_variable_set("@attributes", @attributes)
374
570
  became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
375
- became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
376
571
  became.instance_variable_set("@new_record", new_record?)
377
572
  became.instance_variable_set("@destroyed", destroyed?)
378
573
  became.errors.copy!(errors)
@@ -428,6 +623,7 @@ module ActiveRecord
428
623
  end
429
624
 
430
625
  alias update_attributes update
626
+ deprecate update_attributes: "please, use update instead"
431
627
 
432
628
  # Updates its receiver just like #update but calls #save! instead
433
629
  # of +save+, so an exception is raised if the record is invalid and saving will fail.
@@ -441,6 +637,7 @@ module ActiveRecord
441
637
  end
442
638
 
443
639
  alias update_attributes! update!
640
+ deprecate update_attributes!: "please, use update! instead"
444
641
 
445
642
  # Equivalent to <code>update_columns(name => value)</code>.
446
643
  def update_column(name, value)
@@ -467,8 +664,13 @@ module ActiveRecord
467
664
  raise ActiveRecordError, "cannot update a new record" if new_record?
468
665
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
469
666
 
667
+ attributes = attributes.transform_keys do |key|
668
+ name = key.to_s
669
+ self.class.attribute_aliases[name] || name
670
+ end
671
+
470
672
  attributes.each_key do |key|
471
- verify_readonly_attribute(key.to_s)
673
+ verify_readonly_attribute(key)
472
674
  end
473
675
 
474
676
  id_in_database = self.id_in_database
@@ -478,7 +680,7 @@ module ActiveRecord
478
680
 
479
681
  affected_rows = self.class._update_record(
480
682
  attributes,
481
- self.class.primary_key => id_in_database
683
+ @primary_key => id_in_database
482
684
  )
483
685
 
484
686
  affected_rows == 1
@@ -655,7 +857,9 @@ module ActiveRecord
655
857
  end
656
858
 
657
859
  attribute_names = timestamp_attributes_for_update_in_model
658
- attribute_names |= names.map(&:to_s)
860
+ attribute_names |= names.map!(&:to_s).map! { |name|
861
+ self.class.attribute_aliases[name] || name
862
+ }
659
863
 
660
864
  unless attribute_names.empty?
661
865
  affected_rows = _touch_row(attribute_names, time)
@@ -676,15 +880,14 @@ module ActiveRecord
676
880
  end
677
881
 
678
882
  def _delete_row
679
- self.class._delete_record(self.class.primary_key => id_in_database)
883
+ self.class._delete_record(@primary_key => id_in_database)
680
884
  end
681
885
 
682
886
  def _touch_row(attribute_names, time)
683
887
  time ||= current_time_from_proper_timezone
684
888
 
685
889
  attribute_names.each do |attr_name|
686
- write_attribute(attr_name, time)
687
- clear_attribute_change(attr_name)
890
+ _write_attribute(attr_name, time)
688
891
  end
689
892
 
690
893
  _update_row(attribute_names, "touch")
@@ -693,21 +896,20 @@ module ActiveRecord
693
896
  def _update_row(attribute_names, attempted_action = "update")
694
897
  self.class._update_record(
695
898
  attributes_with_values(attribute_names),
696
- self.class.primary_key => id_in_database
899
+ @primary_key => id_in_database
697
900
  )
698
901
  end
699
902
 
700
- def create_or_update(*args, &block)
903
+ def create_or_update(**, &block)
701
904
  _raise_readonly_record_error if readonly?
702
905
  return false if destroyed?
703
- result = new_record? ? _create_record(&block) : _update_record(*args, &block)
906
+ result = new_record? ? _create_record(&block) : _update_record(&block)
704
907
  result != false
705
908
  end
706
909
 
707
910
  # Updates the associated record with values matching those of the instance attributes.
708
911
  # Returns the number of affected rows.
709
912
  def _update_record(attribute_names = self.attribute_names)
710
- attribute_names &= self.class.column_names
711
913
  attribute_names = attributes_for_update(attribute_names)
712
914
 
713
915
  if attribute_names.empty?
@@ -726,11 +928,13 @@ module ActiveRecord
726
928
  # Creates a record with values matching those of the instance attributes
727
929
  # and returns its id.
728
930
  def _create_record(attribute_names = self.attribute_names)
729
- attribute_names &= self.class.column_names
730
- attributes_values = attributes_with_values_for_create(attribute_names)
931
+ attribute_names = attributes_for_create(attribute_names)
932
+
933
+ new_id = self.class._insert_record(
934
+ attributes_with_values(attribute_names)
935
+ )
731
936
 
732
- new_id = self.class._insert_record(attributes_values)
733
- self.id ||= new_id if self.class.primary_key
937
+ self.id ||= new_id if @primary_key
734
938
 
735
939
  @new_record = false
736
940
 
@@ -750,6 +954,8 @@ module ActiveRecord
750
954
  @_association_destroy_exception = nil
751
955
  end
752
956
 
957
+ # The name of the method used to touch a +belongs_to+ association when the
958
+ # +:touch+ option is used.
753
959
  def belongs_to_touch_method
754
960
  :touch
755
961
  end
@@ -26,15 +26,22 @@ module ActiveRecord
26
26
  end
27
27
 
28
28
  def self.run
29
- ActiveRecord::Base.connection_handler.connection_pool_list.
30
- reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
29
+ pools = []
30
+
31
+ ActiveRecord::Base.connection_handlers.each do |key, handler|
32
+ pools << handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
33
+ end
34
+
35
+ pools.flatten
31
36
  end
32
37
 
33
38
  def self.complete(pools)
34
39
  pools.each { |pool| pool.disable_query_cache! }
35
40
 
36
- ActiveRecord::Base.connection_handler.connection_pool_list.each do |pool|
37
- pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
41
+ ActiveRecord::Base.connection_handlers.each do |_, handler|
42
+ handler.connection_pool_list.each do |pool|
43
+ pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
44
+ end
38
45
  end
39
46
  end
40
47