activerecord 5.2.8.1 → 6.0.6.1

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

Potentially problematic release.


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

Files changed (294) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +938 -573
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/advisory_lock_base.rb +18 -0
  7. data/lib/active_record/aggregations.rb +4 -3
  8. data/lib/active_record/association_relation.rb +10 -8
  9. data/lib/active_record/associations/alias_tracker.rb +0 -1
  10. data/lib/active_record/associations/association.rb +55 -19
  11. data/lib/active_record/associations/association_scope.rb +11 -7
  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 +3 -13
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  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 +19 -23
  22. data/lib/active_record/associations/collection_proxy.rb +14 -17
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -11
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  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/join_association.rb +16 -10
  29. data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
  30. data/lib/active_record/associations/join_dependency.rb +47 -30
  31. data/lib/active_record/associations/preloader/association.rb +61 -41
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/preloader.rb +44 -33
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/associations/through_association.rb +1 -1
  36. data/lib/active_record/associations.rb +21 -16
  37. data/lib/active_record/attribute_assignment.rb +7 -11
  38. data/lib/active_record/attribute_decorators.rb +0 -2
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
  40. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  42. data/lib/active_record/attribute_methods/query.rb +2 -3
  43. data/lib/active_record/attribute_methods/read.rb +15 -54
  44. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  46. data/lib/active_record/attribute_methods/write.rb +17 -25
  47. data/lib/active_record/attribute_methods.rb +28 -100
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +12 -14
  50. data/lib/active_record/base.rb +2 -3
  51. data/lib/active_record/callbacks.rb +6 -21
  52. data/lib/active_record/coders/yaml_column.rb +15 -6
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +77 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
  65. data/lib/active_record/connection_adapters/column.rb +17 -13
  66. data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
  67. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  68. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
  70. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  71. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
  73. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  74. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  75. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  76. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  89. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
  98. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
  101. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  102. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
  107. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  108. data/lib/active_record/connection_handling.rb +139 -26
  109. data/lib/active_record/core.rb +108 -67
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations/database_config.rb +37 -0
  112. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  113. data/lib/active_record/database_configurations/url_config.rb +78 -0
  114. data/lib/active_record/database_configurations.rb +233 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +44 -7
  117. data/lib/active_record/errors.rb +15 -7
  118. data/lib/active_record/explain.rb +1 -2
  119. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  120. data/lib/active_record/fixture_set/render_context.rb +17 -0
  121. data/lib/active_record/fixture_set/table_row.rb +152 -0
  122. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  123. data/lib/active_record/fixtures.rb +144 -474
  124. data/lib/active_record/gem_version.rb +3 -3
  125. data/lib/active_record/inheritance.rb +13 -6
  126. data/lib/active_record/insert_all.rb +179 -0
  127. data/lib/active_record/integration.rb +68 -16
  128. data/lib/active_record/internal_metadata.rb +11 -3
  129. data/lib/active_record/locking/optimistic.rb +14 -7
  130. data/lib/active_record/locking/pessimistic.rb +3 -3
  131. data/lib/active_record/log_subscriber.rb +8 -27
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector.rb +74 -0
  135. data/lib/active_record/migration/command_recorder.rb +54 -22
  136. data/lib/active_record/migration/compatibility.rb +79 -52
  137. data/lib/active_record/migration/join_table.rb +0 -1
  138. data/lib/active_record/migration.rb +104 -85
  139. data/lib/active_record/model_schema.rb +62 -11
  140. data/lib/active_record/nested_attributes.rb +2 -4
  141. data/lib/active_record/no_touching.rb +9 -2
  142. data/lib/active_record/null_relation.rb +0 -1
  143. data/lib/active_record/persistence.rb +232 -29
  144. data/lib/active_record/query_cache.rb +11 -4
  145. data/lib/active_record/querying.rb +33 -21
  146. data/lib/active_record/railtie.rb +80 -61
  147. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  148. data/lib/active_record/railties/controller_runtime.rb +30 -35
  149. data/lib/active_record/railties/databases.rake +199 -46
  150. data/lib/active_record/reflection.rb +51 -51
  151. data/lib/active_record/relation/batches.rb +13 -11
  152. data/lib/active_record/relation/calculations.rb +55 -49
  153. data/lib/active_record/relation/delegation.rb +35 -50
  154. data/lib/active_record/relation/finder_methods.rb +23 -28
  155. data/lib/active_record/relation/from_clause.rb +4 -0
  156. data/lib/active_record/relation/merger.rb +12 -17
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  158. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  159. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  160. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  161. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  162. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  163. data/lib/active_record/relation/predicate_builder.rb +5 -11
  164. data/lib/active_record/relation/query_attribute.rb +13 -8
  165. data/lib/active_record/relation/query_methods.rb +234 -69
  166. data/lib/active_record/relation/spawn_methods.rb +1 -2
  167. data/lib/active_record/relation/where_clause.rb +14 -11
  168. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  169. data/lib/active_record/relation.rb +326 -81
  170. data/lib/active_record/result.rb +30 -12
  171. data/lib/active_record/sanitization.rb +32 -40
  172. data/lib/active_record/schema.rb +2 -11
  173. data/lib/active_record/schema_dumper.rb +22 -7
  174. data/lib/active_record/schema_migration.rb +6 -2
  175. data/lib/active_record/scoping/default.rb +4 -6
  176. data/lib/active_record/scoping/named.rb +25 -16
  177. data/lib/active_record/scoping.rb +8 -9
  178. data/lib/active_record/statement_cache.rb +30 -3
  179. data/lib/active_record/store.rb +87 -8
  180. data/lib/active_record/suppressor.rb +2 -2
  181. data/lib/active_record/table_metadata.rb +23 -15
  182. data/lib/active_record/tasks/database_tasks.rb +194 -25
  183. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
  184. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
  185. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
  186. data/lib/active_record/test_databases.rb +23 -0
  187. data/lib/active_record/test_fixtures.rb +243 -0
  188. data/lib/active_record/timestamp.rb +39 -26
  189. data/lib/active_record/touch_later.rb +5 -4
  190. data/lib/active_record/transactions.rb +64 -73
  191. data/lib/active_record/translation.rb +1 -1
  192. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  193. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  194. data/lib/active_record/type/serialized.rb +0 -1
  195. data/lib/active_record/type/time.rb +10 -0
  196. data/lib/active_record/type/type_map.rb +0 -1
  197. data/lib/active_record/type/unsigned_integer.rb +0 -1
  198. data/lib/active_record/type.rb +3 -5
  199. data/lib/active_record/type_caster/connection.rb +15 -14
  200. data/lib/active_record/type_caster/map.rb +1 -4
  201. data/lib/active_record/validations/associated.rb +0 -1
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/active_record/validations.rb +3 -3
  204. data/lib/active_record.rb +10 -2
  205. data/lib/arel/alias_predication.rb +9 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/attributes.rb +22 -0
  208. data/lib/arel/collectors/bind.rb +24 -0
  209. data/lib/arel/collectors/composite.rb +31 -0
  210. data/lib/arel/collectors/plain_string.rb +20 -0
  211. data/lib/arel/collectors/sql_string.rb +20 -0
  212. data/lib/arel/collectors/substitute_binds.rb +28 -0
  213. data/lib/arel/crud.rb +42 -0
  214. data/lib/arel/delete_manager.rb +18 -0
  215. data/lib/arel/errors.rb +9 -0
  216. data/lib/arel/expressions.rb +29 -0
  217. data/lib/arel/factory_methods.rb +49 -0
  218. data/lib/arel/insert_manager.rb +49 -0
  219. data/lib/arel/math.rb +45 -0
  220. data/lib/arel/nodes/and.rb +32 -0
  221. data/lib/arel/nodes/ascending.rb +23 -0
  222. data/lib/arel/nodes/binary.rb +52 -0
  223. data/lib/arel/nodes/bind_param.rb +36 -0
  224. data/lib/arel/nodes/case.rb +55 -0
  225. data/lib/arel/nodes/casted.rb +50 -0
  226. data/lib/arel/nodes/comment.rb +29 -0
  227. data/lib/arel/nodes/count.rb +12 -0
  228. data/lib/arel/nodes/delete_statement.rb +45 -0
  229. data/lib/arel/nodes/descending.rb +23 -0
  230. data/lib/arel/nodes/equality.rb +18 -0
  231. data/lib/arel/nodes/extract.rb +24 -0
  232. data/lib/arel/nodes/false.rb +16 -0
  233. data/lib/arel/nodes/full_outer_join.rb +8 -0
  234. data/lib/arel/nodes/function.rb +44 -0
  235. data/lib/arel/nodes/grouping.rb +8 -0
  236. data/lib/arel/nodes/in.rb +8 -0
  237. data/lib/arel/nodes/infix_operation.rb +80 -0
  238. data/lib/arel/nodes/inner_join.rb +8 -0
  239. data/lib/arel/nodes/insert_statement.rb +37 -0
  240. data/lib/arel/nodes/join_source.rb +20 -0
  241. data/lib/arel/nodes/matches.rb +18 -0
  242. data/lib/arel/nodes/named_function.rb +23 -0
  243. data/lib/arel/nodes/node.rb +50 -0
  244. data/lib/arel/nodes/node_expression.rb +13 -0
  245. data/lib/arel/nodes/outer_join.rb +8 -0
  246. data/lib/arel/nodes/over.rb +15 -0
  247. data/lib/arel/nodes/regexp.rb +16 -0
  248. data/lib/arel/nodes/right_outer_join.rb +8 -0
  249. data/lib/arel/nodes/select_core.rb +67 -0
  250. data/lib/arel/nodes/select_statement.rb +41 -0
  251. data/lib/arel/nodes/sql_literal.rb +16 -0
  252. data/lib/arel/nodes/string_join.rb +11 -0
  253. data/lib/arel/nodes/table_alias.rb +27 -0
  254. data/lib/arel/nodes/terminal.rb +16 -0
  255. data/lib/arel/nodes/true.rb +16 -0
  256. data/lib/arel/nodes/unary.rb +45 -0
  257. data/lib/arel/nodes/unary_operation.rb +20 -0
  258. data/lib/arel/nodes/unqualified_column.rb +22 -0
  259. data/lib/arel/nodes/update_statement.rb +41 -0
  260. data/lib/arel/nodes/values_list.rb +9 -0
  261. data/lib/arel/nodes/window.rb +126 -0
  262. data/lib/arel/nodes/with.rb +11 -0
  263. data/lib/arel/nodes.rb +68 -0
  264. data/lib/arel/order_predications.rb +13 -0
  265. data/lib/arel/predications.rb +256 -0
  266. data/lib/arel/select_manager.rb +271 -0
  267. data/lib/arel/table.rb +110 -0
  268. data/lib/arel/tree_manager.rb +72 -0
  269. data/lib/arel/update_manager.rb +34 -0
  270. data/lib/arel/visitors/depth_first.rb +203 -0
  271. data/lib/arel/visitors/dot.rb +296 -0
  272. data/lib/arel/visitors/ibm_db.rb +34 -0
  273. data/lib/arel/visitors/informix.rb +62 -0
  274. data/lib/arel/visitors/mssql.rb +156 -0
  275. data/lib/arel/visitors/mysql.rb +83 -0
  276. data/lib/arel/visitors/oracle.rb +158 -0
  277. data/lib/arel/visitors/oracle12.rb +65 -0
  278. data/lib/arel/visitors/postgresql.rb +109 -0
  279. data/lib/arel/visitors/sqlite.rb +38 -0
  280. data/lib/arel/visitors/to_sql.rb +888 -0
  281. data/lib/arel/visitors/visitor.rb +45 -0
  282. data/lib/arel/visitors/where_sql.rb +22 -0
  283. data/lib/arel/visitors.rb +20 -0
  284. data/lib/arel/window_predications.rb +9 -0
  285. data/lib/arel.rb +62 -0
  286. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  287. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  288. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  289. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  290. data/lib/rails/generators/active_record/migration.rb +14 -2
  291. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  292. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  293. metadata +113 -26
  294. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -102,6 +102,21 @@ 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. Note that using
119
+ # a non-unique column can result in non-deterministic results.
105
120
  included do
106
121
  mattr_accessor :primary_key_prefix_type, instance_writer: false
107
122
 
@@ -110,6 +125,7 @@ module ActiveRecord
110
125
  class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
111
126
  class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
112
127
  class_attribute :pluralize_table_names, instance_writer: false, default: true
128
+ class_attribute :implicit_order_column, instance_accessor: false
113
129
 
114
130
  self.protected_environments = ["production"]
115
131
  self.inheritance_column = "type"
@@ -218,11 +234,11 @@ module ActiveRecord
218
234
  end
219
235
 
220
236
  def full_table_name_prefix #:nodoc:
221
- (parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
237
+ (module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
222
238
  end
223
239
 
224
240
  def full_table_name_suffix #:nodoc:
225
- (parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
241
+ (module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
226
242
  end
227
243
 
228
244
  # The array of names of environments where destructive actions should be prohibited. By default,
@@ -271,12 +287,41 @@ module ActiveRecord
271
287
 
272
288
  # Sets the columns names the model should ignore. Ignored columns won't have attribute
273
289
  # accessors defined, and won't be referenced in SQL queries.
290
+ #
291
+ # A common usage pattern for this method is to ensure all references to an attribute
292
+ # have been removed and deployed, before a migration to drop the column from the database
293
+ # has been deployed and run. Using this two step approach to dropping columns ensures there
294
+ # is no code that raises errors due to having a cached schema in memory at the time the
295
+ # schema migration is run.
296
+ #
297
+ # For example, given a model where you want to drop the "category" attribute, first mark it
298
+ # as ignored:
299
+ #
300
+ # class Project < ActiveRecord::Base
301
+ # # schema:
302
+ # # id :bigint
303
+ # # name :string, limit: 255
304
+ # # category :string, limit: 255
305
+ #
306
+ # self.ignored_columns = [:category]
307
+ # end
308
+ #
309
+ # The schema still contains `category`, but now the model omits it, so any meta-driven code or
310
+ # schema caching will not attempt to use the column:
311
+ #
312
+ # Project.columns_hash["category"] => nil
313
+ #
314
+ # You will get an error if accessing that attribute directly, so ensure all usages of the
315
+ # column are removed (automated tests can help you find any usages).
316
+ #
317
+ # user = Project.create!(name: "First Project")
318
+ # user.category # => raises NoMethodError
274
319
  def ignored_columns=(columns)
275
320
  @ignored_columns = columns.map(&:to_s)
276
321
  end
277
322
 
278
323
  def sequence_name
279
- if base_class == self
324
+ if base_class?
280
325
  @sequence_name ||= reset_sequence_name
281
326
  else
282
327
  (@sequence_name ||= nil) || base_class.sequence_name
@@ -388,6 +433,11 @@ module ActiveRecord
388
433
  @column_names ||= columns.map(&:name)
389
434
  end
390
435
 
436
+ def symbol_column_to_string(name_symbol) # :nodoc:
437
+ @symbol_column_to_string_name_hash ||= column_names.index_by(&:to_sym)
438
+ @symbol_column_to_string_name_hash[name_symbol]
439
+ end
440
+
391
441
  # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
392
442
  # and columns used for single table inheritance have been removed.
393
443
  def content_columns
@@ -435,13 +485,11 @@ module ActiveRecord
435
485
  end
436
486
 
437
487
  protected
438
-
439
488
  def initialize_load_schema_monitor
440
489
  @load_schema_monitor = Monitor.new
441
490
  end
442
491
 
443
492
  private
444
-
445
493
  def inherited(child_class)
446
494
  super
447
495
  child_class.initialize_load_schema_monitor
@@ -459,6 +507,9 @@ module ActiveRecord
459
507
  load_schema!
460
508
 
461
509
  @schema_loaded = true
510
+ rescue
511
+ reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
512
+ raise
462
513
  end
463
514
  end
464
515
 
@@ -477,6 +528,7 @@ module ActiveRecord
477
528
  def reload_schema_from_cache
478
529
  @arel_table = nil
479
530
  @column_names = nil
531
+ @symbol_column_to_string_name_hash = nil
480
532
  @attribute_types = nil
481
533
  @content_columns = nil
482
534
  @default_attributes = nil
@@ -501,19 +553,18 @@ module ActiveRecord
501
553
 
502
554
  # Computes and returns a table name according to default conventions.
503
555
  def compute_table_name
504
- base = base_class
505
- if self == base
556
+ if base_class?
506
557
  # 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
558
+ if module_parent < Base && !module_parent.abstract_class?
559
+ contained = module_parent.table_name
560
+ contained = contained.singularize if module_parent.pluralize_table_names
510
561
  contained += "_"
511
562
  end
512
563
 
513
564
  "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
514
565
  else
515
566
  # STI subclasses always use their superclass' table.
516
- base.table_name
567
+ base_class.table_name
517
568
  end
518
569
  end
519
570
  end
@@ -354,7 +354,6 @@ module ActiveRecord
354
354
  end
355
355
 
356
356
  private
357
-
358
357
  # Generates a writer method for this association. Serves as a point for
359
358
  # accessing the objects in the association. For example, this method
360
359
  # could generate the following:
@@ -386,7 +385,6 @@ module ActiveRecord
386
385
  end
387
386
 
388
387
  private
389
-
390
388
  # Attribute hash keys that should not be assigned as normal attributes.
391
389
  # These hash keys are nested attributes implementation details.
392
390
  UNASSIGNABLE_KEYS = %w( id _destroy )
@@ -426,7 +424,7 @@ module ActiveRecord
426
424
  existing_record.assign_attributes(assignable_attributes)
427
425
  association(association_name).initialize_attributes(existing_record)
428
426
  else
429
- method = "build_#{association_name}"
427
+ method = :"build_#{association_name}"
430
428
  if respond_to?(method)
431
429
  send(method, assignable_attributes)
432
430
  else
@@ -501,7 +499,7 @@ module ActiveRecord
501
499
 
502
500
  if attributes["id"].blank?
503
501
  unless reject_new_record?(association_name, attributes)
504
- association.build(attributes.except(*UNASSIGNABLE_KEYS))
502
+ association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
505
503
  end
506
504
  elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
507
505
  unless call_reject_if(association_name, attributes)
@@ -43,15 +43,22 @@ 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
49
56
 
50
- def touch_later(*) # :nodoc:
57
+ def touch_later(*, **) # :nodoc:
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
  #
@@ -229,20 +424,20 @@ 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
427
+ sync_with_transaction_state if @transaction_state&.finalized?
233
428
  @new_record
234
429
  end
235
430
 
236
431
  # Returns true if this object has been destroyed, otherwise returns false.
237
432
  def destroyed?
238
- sync_with_transaction_state
433
+ sync_with_transaction_state if @transaction_state&.finalized?
239
434
  @destroyed
240
435
  end
241
436
 
242
437
  # Returns true if the record is persisted, i.e. it's not a new record and it was
243
438
  # not destroyed, otherwise returns false.
244
439
  def persisted?
245
- sync_with_transaction_state
440
+ sync_with_transaction_state if @transaction_state&.finalized?
246
441
  !(@new_record || @destroyed)
247
442
  end
248
443
 
@@ -271,8 +466,8 @@ module ActiveRecord
271
466
  #
272
467
  # Attributes marked as readonly are silently ignored if the record is
273
468
  # being updated.
274
- def save(*args, &block)
275
- create_or_update(*args, &block)
469
+ def save(*args, **options, &block)
470
+ create_or_update(*args, **options, &block)
276
471
  rescue ActiveRecord::RecordInvalid
277
472
  false
278
473
  end
@@ -304,8 +499,8 @@ module ActiveRecord
304
499
  # being updated.
305
500
  #
306
501
  # 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))
502
+ def save!(*args, **options, &block)
503
+ create_or_update(*args, **options, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
309
504
  end
310
505
 
311
506
  # Deletes the record in the database and freezes this instance to
@@ -336,7 +531,6 @@ module ActiveRecord
336
531
  def destroy
337
532
  _raise_readonly_record_error if readonly?
338
533
  destroy_associations
339
- self.class.connection.add_transaction_record(self)
340
534
  @_trigger_destroy_callback = if persisted?
341
535
  destroy_row > 0
342
536
  else
@@ -374,7 +568,6 @@ module ActiveRecord
374
568
  became.send(:initialize)
375
569
  became.instance_variable_set("@attributes", @attributes)
376
570
  became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
377
- became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
378
571
  became.instance_variable_set("@new_record", new_record?)
379
572
  became.instance_variable_set("@destroyed", destroyed?)
380
573
  became.errors.copy!(errors)
@@ -430,6 +623,7 @@ module ActiveRecord
430
623
  end
431
624
 
432
625
  alias update_attributes update
626
+ deprecate update_attributes: "please, use update instead"
433
627
 
434
628
  # Updates its receiver just like #update but calls #save! instead
435
629
  # of +save+, so an exception is raised if the record is invalid and saving will fail.
@@ -443,6 +637,7 @@ module ActiveRecord
443
637
  end
444
638
 
445
639
  alias update_attributes! update!
640
+ deprecate update_attributes!: "please, use update! instead"
446
641
 
447
642
  # Equivalent to <code>update_columns(name => value)</code>.
448
643
  def update_column(name, value)
@@ -469,8 +664,13 @@ module ActiveRecord
469
664
  raise ActiveRecordError, "cannot update a new record" if new_record?
470
665
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
471
666
 
667
+ attributes = attributes.transform_keys do |key|
668
+ name = key.to_s
669
+ self.class.attribute_aliases[name] || name
670
+ end
671
+
472
672
  attributes.each_key do |key|
473
- verify_readonly_attribute(key.to_s)
673
+ verify_readonly_attribute(key)
474
674
  end
475
675
 
476
676
  id_in_database = self.id_in_database
@@ -480,7 +680,7 @@ module ActiveRecord
480
680
 
481
681
  affected_rows = self.class._update_record(
482
682
  attributes,
483
- self.class.primary_key => id_in_database
683
+ @primary_key => id_in_database
484
684
  )
485
685
 
486
686
  affected_rows == 1
@@ -657,7 +857,9 @@ module ActiveRecord
657
857
  end
658
858
 
659
859
  attribute_names = timestamp_attributes_for_update_in_model
660
- attribute_names |= names.map(&:to_s)
860
+ attribute_names |= names.map!(&:to_s).map! { |name|
861
+ self.class.attribute_aliases[name] || name
862
+ }
661
863
 
662
864
  unless attribute_names.empty?
663
865
  affected_rows = _touch_row(attribute_names, time)
@@ -668,7 +870,6 @@ module ActiveRecord
668
870
  end
669
871
 
670
872
  private
671
-
672
873
  # A hook to be overridden by association modules.
673
874
  def destroy_associations
674
875
  end
@@ -678,15 +879,14 @@ module ActiveRecord
678
879
  end
679
880
 
680
881
  def _delete_row
681
- self.class._delete_record(self.class.primary_key => id_in_database)
882
+ self.class._delete_record(@primary_key => id_in_database)
682
883
  end
683
884
 
684
885
  def _touch_row(attribute_names, time)
685
886
  time ||= current_time_from_proper_timezone
686
887
 
687
888
  attribute_names.each do |attr_name|
688
- write_attribute(attr_name, time)
689
- clear_attribute_change(attr_name)
889
+ _write_attribute(attr_name, time)
690
890
  end
691
891
 
692
892
  _update_row(attribute_names, "touch")
@@ -695,21 +895,20 @@ module ActiveRecord
695
895
  def _update_row(attribute_names, attempted_action = "update")
696
896
  self.class._update_record(
697
897
  attributes_with_values(attribute_names),
698
- self.class.primary_key => id_in_database
898
+ @primary_key => id_in_database
699
899
  )
700
900
  end
701
901
 
702
- def create_or_update(*args, &block)
902
+ def create_or_update(**, &block)
703
903
  _raise_readonly_record_error if readonly?
704
904
  return false if destroyed?
705
- result = new_record? ? _create_record(&block) : _update_record(*args, &block)
905
+ result = new_record? ? _create_record(&block) : _update_record(&block)
706
906
  result != false
707
907
  end
708
908
 
709
909
  # Updates the associated record with values matching those of the instance attributes.
710
910
  # Returns the number of affected rows.
711
911
  def _update_record(attribute_names = self.attribute_names)
712
- attribute_names &= self.class.column_names
713
912
  attribute_names = attributes_for_update(attribute_names)
714
913
 
715
914
  if attribute_names.empty?
@@ -728,11 +927,13 @@ module ActiveRecord
728
927
  # Creates a record with values matching those of the instance attributes
729
928
  # and returns its id.
730
929
  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)
930
+ attribute_names = attributes_for_create(attribute_names)
931
+
932
+ new_id = self.class._insert_record(
933
+ attributes_with_values(attribute_names)
934
+ )
733
935
 
734
- new_id = self.class._insert_record(attributes_values)
735
- self.id ||= new_id if self.class.primary_key
936
+ self.id ||= new_id if @primary_key
736
937
 
737
938
  @new_record = false
738
939
 
@@ -752,6 +953,8 @@ module ActiveRecord
752
953
  @_association_destroy_exception = nil
753
954
  end
754
955
 
956
+ # The name of the method used to touch a +belongs_to+ association when the
957
+ # +:touch+ option is used.
755
958
  def belongs_to_touch_method
756
959
  :touch
757
960
  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