activerecord 5.2.7 → 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 +987 -584
  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 +23 -2
  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 +117 -66
  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 +4 -4
  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 -43
  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 +116 -29
  294. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -208,8 +208,8 @@ module ActiveRecord
208
208
  # Note that "TRUNCATE" is also a MySQL DDL statement!
209
209
  module ClassMethods
210
210
  # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
211
- def transaction(options = {}, &block)
212
- connection.transaction(options, &block)
211
+ def transaction(**options, &block)
212
+ connection.transaction(**options, &block)
213
213
  end
214
214
 
215
215
  def before_commit(*args, &block) # :nodoc:
@@ -234,6 +234,12 @@ module ActiveRecord
234
234
  set_callback(:commit, :after, *args, &block)
235
235
  end
236
236
 
237
+ # Shortcut for <tt>after_commit :hook, on: [ :create, :update ]</tt>.
238
+ def after_save_commit(*args, &block)
239
+ set_options_for_callbacks!(args, on: [ :create, :update ])
240
+ set_callback(:commit, :after, *args, &block)
241
+ end
242
+
237
243
  # Shortcut for <tt>after_commit :hook, on: :create</tt>.
238
244
  def after_create_commit(*args, &block)
239
245
  set_options_for_callbacks!(args, on: :create)
@@ -276,7 +282,6 @@ module ActiveRecord
276
282
  end
277
283
 
278
284
  private
279
-
280
285
  def set_options_for_callbacks!(args, enforced_options = {})
281
286
  options = args.extract_options!.merge!(enforced_options)
282
287
  args << options
@@ -298,36 +303,23 @@ module ActiveRecord
298
303
 
299
304
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
300
305
  def transaction(options = {}, &block)
301
- self.class.transaction(options, &block)
306
+ self.class.transaction(**options, &block)
302
307
  end
303
308
 
304
309
  def destroy #:nodoc:
305
310
  with_transaction_returning_status { super }
306
311
  end
307
312
 
308
- def save(*) #:nodoc:
309
- rollback_active_record_state! do
310
- with_transaction_returning_status { super }
311
- end
312
- end
313
-
314
- def save!(*) #:nodoc:
313
+ def save(*, **) #:nodoc:
315
314
  with_transaction_returning_status { super }
316
315
  end
317
316
 
318
- def touch(*) #:nodoc:
317
+ def save!(*, **) #:nodoc:
319
318
  with_transaction_returning_status { super }
320
319
  end
321
320
 
322
- # Reset id and @new_record if the transaction rolls back.
323
- def rollback_active_record_state!
324
- remember_transaction_record_state
325
- yield
326
- rescue Exception
327
- restore_transaction_record_state
328
- raise
329
- ensure
330
- clear_transaction_record_state
321
+ def touch(*, **) #:nodoc:
322
+ with_transaction_returning_status { super }
331
323
  end
332
324
 
333
325
  def before_committed! # :nodoc:
@@ -341,13 +333,13 @@ module ActiveRecord
341
333
  # but call it after the commit of a destroyed object.
342
334
  def committed!(should_run_callbacks: true) #:nodoc:
343
335
  force_clear_transaction_record_state
344
- if should_run_callbacks && (destroyed? || persisted?)
336
+ if should_run_callbacks
345
337
  @_committed_already_called = true
346
338
  _run_commit_without_transaction_enrollment_callbacks
347
339
  _run_commit_callbacks
348
340
  end
349
341
  ensure
350
- @_committed_already_called = false
342
+ @_committed_already_called = @_trigger_update_callback = @_trigger_destroy_callback = false
351
343
  end
352
344
 
353
345
  # Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
@@ -360,18 +352,7 @@ module ActiveRecord
360
352
  ensure
361
353
  restore_transaction_record_state(force_restore_state)
362
354
  clear_transaction_record_state
363
- end
364
-
365
- # Add the record to the current transaction so that the #after_rollback and #after_commit callbacks
366
- # can be called.
367
- def add_to_transaction
368
- if has_transactional_callbacks?
369
- self.class.connection.add_transaction_record(self)
370
- else
371
- sync_with_transaction_state
372
- set_transaction_state(self.class.connection.transaction_state)
373
- end
374
- remember_transaction_record_state
355
+ @_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state
375
356
  end
376
357
 
377
358
  # Executes +method+ within a transaction and captures its return value as a
@@ -383,35 +364,40 @@ module ActiveRecord
383
364
  def with_transaction_returning_status
384
365
  status = nil
385
366
  self.class.transaction do
386
- add_to_transaction
367
+ if has_transactional_callbacks?
368
+ add_to_transaction
369
+ else
370
+ sync_with_transaction_state if @transaction_state&.finalized?
371
+ @transaction_state = self.class.connection.transaction_state
372
+ end
373
+ remember_transaction_record_state
374
+
387
375
  status = yield
388
376
  raise ActiveRecord::Rollback unless status
389
377
  end
390
378
  status
391
- ensure
392
- if @transaction_state && @transaction_state.committed?
393
- clear_transaction_record_state
394
- end
395
379
  end
396
380
 
397
- protected
398
- attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
381
+ def trigger_transactional_callbacks? # :nodoc:
382
+ (@_new_record_before_last_commit || _trigger_update_callback) && persisted? ||
383
+ _trigger_destroy_callback && destroyed?
384
+ end
399
385
 
400
386
  private
387
+ attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
401
388
 
402
389
  # Save the new record state and id of a record so it can be restored later if a transaction fails.
403
390
  def remember_transaction_record_state
404
- @_start_transaction_state.reverse_merge!(
391
+ @_start_transaction_state ||= {
405
392
  id: id,
406
393
  new_record: @new_record,
407
394
  destroyed: @destroyed,
395
+ attributes: @attributes,
408
396
  frozen?: frozen?,
409
- )
410
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
411
- remember_new_record_before_last_commit
412
- end
397
+ level: 0
398
+ }
399
+ @_start_transaction_state[:level] += 1
413
400
 
414
- def remember_new_record_before_last_commit
415
401
  if _committed_already_called
416
402
  @_new_record_before_last_commit = false
417
403
  else
@@ -421,27 +407,32 @@ module ActiveRecord
421
407
 
422
408
  # Clear the new record state and id of a record.
423
409
  def clear_transaction_record_state
424
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
410
+ return unless @_start_transaction_state
411
+ @_start_transaction_state[:level] -= 1
425
412
  force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
426
413
  end
427
414
 
428
415
  # Force to clear the transaction record state.
429
416
  def force_clear_transaction_record_state
430
- @_start_transaction_state.clear
417
+ @_start_transaction_state = nil
418
+ @transaction_state = nil
431
419
  end
432
420
 
433
421
  # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
434
- def restore_transaction_record_state(force = false)
435
- unless @_start_transaction_state.empty?
436
- transaction_level = (@_start_transaction_state[:level] || 0) - 1
437
- if transaction_level < 1 || force
438
- restore_state = @_start_transaction_state
439
- thaw
422
+ def restore_transaction_record_state(force_restore_state = false)
423
+ if restore_state = @_start_transaction_state
424
+ if force_restore_state || restore_state[:level] <= 1
440
425
  @new_record = restore_state[:new_record]
441
426
  @destroyed = restore_state[:destroyed]
442
- pk = self.class.primary_key
443
- if pk && _read_attribute(pk) != restore_state[:id]
444
- _write_attribute(pk, restore_state[:id])
427
+ @attributes = restore_state[:attributes].map do |attr|
428
+ value = @attributes.fetch_value(attr.name)
429
+ attr = attr.with_value_from_user(value) if attr.value != value
430
+ attr
431
+ end
432
+ @mutations_from_database = nil
433
+ @mutations_before_last_save = nil
434
+ if @attributes.fetch_value(@primary_key) != restore_state[:id]
435
+ @attributes.write_from_user(@primary_key, restore_state[:id])
445
436
  end
446
437
  freeze if restore_state[:frozen?]
447
438
  end
@@ -462,8 +453,10 @@ module ActiveRecord
462
453
  end
463
454
  end
464
455
 
465
- def set_transaction_state(state)
466
- @transaction_state = state
456
+ # Add the record to the current transaction so that the #after_rollback and #after_commit
457
+ # callbacks can be called.
458
+ def add_to_transaction
459
+ self.class.connection.add_transaction_record(self)
467
460
  end
468
461
 
469
462
  def has_transactional_callbacks?
@@ -483,19 +476,17 @@ module ActiveRecord
483
476
  # This method checks to see if the ActiveRecord object's state reflects
484
477
  # the TransactionState, and rolls back or commits the Active Record object
485
478
  # as appropriate.
486
- #
487
- # Since Active Record objects can be inside multiple transactions, this
488
- # method recursively goes through the parent of the TransactionState and
489
- # checks if the Active Record object reflects the state of the object.
490
479
  def sync_with_transaction_state
491
- update_attributes_from_transaction_state(@transaction_state)
492
- end
493
-
494
- def update_attributes_from_transaction_state(transaction_state)
495
- if transaction_state && transaction_state.finalized?
496
- restore_transaction_record_state(transaction_state.fully_rolledback?) if transaction_state.rolledback?
497
- force_clear_transaction_record_state if transaction_state.fully_committed?
498
- clear_transaction_record_state if transaction_state.fully_completed?
480
+ if transaction_state = @transaction_state
481
+ if transaction_state.fully_committed?
482
+ force_clear_transaction_record_state
483
+ elsif transaction_state.committed?
484
+ clear_transaction_record_state
485
+ elsif transaction_state.rolledback?
486
+ force_restore_state = transaction_state.fully_rolledback?
487
+ restore_transaction_record_state(force_restore_state)
488
+ clear_transaction_record_state
489
+ end
499
490
  end
500
491
  end
501
492
  end
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  classes = [klass]
11
11
  return classes if klass == ActiveRecord::Base
12
12
 
13
- while klass != klass.base_class
13
+ while !klass.base_class?
14
14
  classes << klass = klass.superclass
15
15
  end
16
16
  classes
@@ -11,14 +11,13 @@ module ActiveRecord
11
11
  end
12
12
 
13
13
  private
14
-
15
14
  def registration_klass
16
15
  Registration
17
16
  end
18
17
 
19
- def find_registration(symbol, *args)
18
+ def find_registration(symbol, *args, **kwargs)
20
19
  registrations
21
- .select { |registration| registration.matches?(symbol, *args) }
20
+ .select { |registration| registration.matches?(symbol, *args, **kwargs) }
22
21
  .max
23
22
  end
24
23
  end
@@ -52,10 +51,7 @@ module ActiveRecord
52
51
  priority <=> other.priority
53
52
  end
54
53
 
55
- # TODO Change this to private once we've dropped Ruby 2.2 support.
56
- # Workaround for Ruby 2.2 "private attribute?" warning.
57
54
  protected
58
-
59
55
  attr_reader :name, :block, :adapter, :override
60
56
 
61
57
  def priority
@@ -74,7 +70,6 @@ module ActiveRecord
74
70
  end
75
71
 
76
72
  private
77
-
78
73
  def matches_adapter?(adapter: nil, **)
79
74
  (self.adapter.nil? || adapter == self.adapter)
80
75
  end
@@ -114,13 +109,8 @@ module ActiveRecord
114
109
  super | 4
115
110
  end
116
111
 
117
- # TODO Change this to private once we've dropped Ruby 2.2 support.
118
- # Workaround for Ruby 2.2 "private attribute?" warning.
119
- protected
120
-
121
- attr_reader :options, :klass
122
-
123
112
  private
113
+ attr_reader :options, :klass
124
114
 
125
115
  def matches_options?(**kwargs)
126
116
  options.all? do |key, value|
@@ -16,7 +16,6 @@ module ActiveRecord
16
16
  end
17
17
 
18
18
  private
19
-
20
19
  def perform_fetch(type, *args, &block)
21
20
  @mapping.fetch(type, block).call(type, *args)
22
21
  end
@@ -56,7 +56,6 @@ module ActiveRecord
56
56
  end
57
57
 
58
58
  private
59
-
60
59
  def default_value?(value)
61
60
  value == coder.load(nil)
62
61
  end
@@ -16,6 +16,16 @@ module ActiveRecord
16
16
  value
17
17
  end
18
18
  end
19
+
20
+ private
21
+ def cast_value(value)
22
+ case value = super
23
+ when Value
24
+ value.__getobj__
25
+ else
26
+ value
27
+ end
28
+ end
19
29
  end
20
30
  end
21
31
  end
@@ -45,7 +45,6 @@ module ActiveRecord
45
45
  end
46
46
 
47
47
  private
48
-
49
48
  def perform_fetch(lookup_key, *args)
50
49
  matching_pair = @mapping.reverse_each.detect do |key, _|
51
50
  key === lookup_key
@@ -4,7 +4,6 @@ module ActiveRecord
4
4
  module Type
5
5
  class UnsignedInteger < ActiveModel::Type::Integer # :nodoc:
6
6
  private
7
-
8
7
  def max_value
9
8
  super * 2
10
9
  end
@@ -47,13 +47,11 @@ module ActiveRecord
47
47
  end
48
48
 
49
49
  private
50
-
51
- def current_adapter_name
52
- ActiveRecord::Base.connection.adapter_name.downcase.to_sym
53
- end
50
+ def current_adapter_name
51
+ ActiveRecord::Base.connection.adapter_name.downcase.to_sym
52
+ end
54
53
  end
55
54
 
56
- Helpers = ActiveModel::Type::Helpers
57
55
  BigInteger = ActiveModel::Type::BigInteger
58
56
  Binary = ActiveModel::Type::Binary
59
57
  Boolean = ActiveModel::Type::Boolean
@@ -8,26 +8,27 @@ module ActiveRecord
8
8
  @table_name = table_name
9
9
  end
10
10
 
11
- def type_cast_for_database(attribute_name, value)
11
+ def type_cast_for_database(attr_name, value)
12
12
  return value if value.is_a?(Arel::Nodes::BindParam)
13
- column = column_for(attribute_name)
14
- connection.type_cast_from_column(column, value)
13
+ type = type_for_attribute(attr_name)
14
+ type.serialize(value)
15
15
  end
16
16
 
17
- # TODO Change this to private once we've dropped Ruby 2.2 support.
18
- # Workaround for Ruby 2.2 "private attribute?" warning.
19
- protected
17
+ def type_for_attribute(attr_name)
18
+ schema_cache = connection.schema_cache
20
19
 
21
- attr_reader :table_name
22
- delegate :connection, to: :@klass
20
+ if schema_cache.data_source_exists?(table_name)
21
+ column = schema_cache.columns_hash(table_name)[attr_name.to_s]
22
+ type = connection.lookup_cast_type_from_column(column) if column
23
+ end
23
24
 
24
- private
25
+ type || Type.default_value
26
+ end
25
27
 
26
- def column_for(attribute_name)
27
- if connection.schema_cache.data_source_exists?(table_name)
28
- connection.schema_cache.columns_hash(table_name)[attribute_name.to_s]
29
- end
30
- end
28
+ delegate :connection, to: :@klass, private: true
29
+
30
+ private
31
+ attr_reader :table_name
31
32
  end
32
33
  end
33
34
  end
@@ -13,10 +13,7 @@ module ActiveRecord
13
13
  type.serialize(value)
14
14
  end
15
15
 
16
- # TODO Change this to private once we've dropped Ruby 2.2 support.
17
- # Workaround for Ruby 2.2 "private attribute?" warning.
18
- protected
19
-
16
+ private
20
17
  attr_reader :types
21
18
  end
22
19
  end
@@ -10,7 +10,6 @@ module ActiveRecord
10
10
  end
11
11
 
12
12
  private
13
-
14
13
  def valid_object?(record)
15
14
  (record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid?
16
15
  end
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  raise ArgumentError, "#{options[:scope]} is not supported format for :scope option. " \
13
13
  "Pass a symbol or an array of symbols instead: `scope: :user_id`"
14
14
  end
15
- super({ case_sensitive: true }.merge!(options))
15
+ super
16
16
  @klass = options[:class]
17
17
  end
18
18
 
@@ -25,7 +25,7 @@ module ActiveRecord
25
25
  if finder_class.primary_key
26
26
  relation = relation.where.not(finder_class.primary_key => record.id_in_database)
27
27
  else
28
- raise UnknownPrimaryKey.new(finder_class, "Can not validate uniqueness for persisted record without primary key.")
28
+ raise UnknownPrimaryKey.new(finder_class, "Cannot validate uniqueness for persisted record without primary key.")
29
29
  end
30
30
  end
31
31
  relation = scope_relation(record, relation)
@@ -56,33 +56,21 @@ module ActiveRecord
56
56
  end
57
57
 
58
58
  def build_relation(klass, attribute, value)
59
- if reflection = klass._reflect_on_association(attribute)
60
- attribute = reflection.foreign_key
61
- value = value.attributes[reflection.klass.primary_key] unless value.nil?
62
- end
63
-
64
- if value.nil?
65
- return klass.unscoped.where!(attribute => value)
66
- end
67
-
68
- # the attribute may be an aliased attribute
69
- if klass.attribute_alias?(attribute)
70
- attribute = klass.attribute_alias(attribute)
59
+ relation = klass.unscoped
60
+ comparison = relation.bind_attribute(attribute, value) do |attr, bind|
61
+ return relation.none! if bind.unboundable?
62
+
63
+ if !options.key?(:case_sensitive) || bind.nil?
64
+ klass.connection.default_uniqueness_comparison(attr, bind, klass)
65
+ elsif options[:case_sensitive]
66
+ klass.connection.case_sensitive_comparison(attr, bind)
67
+ else
68
+ # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
69
+ klass.connection.case_insensitive_comparison(attr, bind)
70
+ end
71
71
  end
72
72
 
73
- attribute_name = attribute.to_s
74
- value = klass.predicate_builder.build_bind_attribute(attribute_name, value)
75
-
76
- table = klass.arel_table
77
- column = klass.columns_hash[attribute_name]
78
-
79
- comparison = if !options[:case_sensitive]
80
- # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
81
- klass.connection.case_insensitive_comparison(table, attribute, column, value)
82
- else
83
- klass.connection.case_sensitive_comparison(table, attribute, column, value)
84
- end
85
- klass.unscoped.where!(comparison)
73
+ relation.where!(comparison)
86
74
  end
87
75
 
88
76
  def scope_relation(record, relation)
@@ -40,15 +40,16 @@ module ActiveRecord
40
40
  include ActiveModel::Validations
41
41
 
42
42
  # The validation process on save can be skipped by passing <tt>validate: false</tt>.
43
+ # The validation context can be changed by passing <tt>context: context</tt>.
43
44
  # The regular {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] method is replaced
44
45
  # with this when the validations module is mixed in, which it is by default.
45
- def save(options = {})
46
+ def save(**options)
46
47
  perform_validations(options) ? super : false
47
48
  end
48
49
 
49
50
  # Attempts to save the record just like {ActiveRecord::Base#save}[rdoc-ref:Base#save] but
50
51
  # will raise an ActiveRecord::RecordInvalid exception instead of returning +false+ if the record is not valid.
51
- def save!(options = {})
52
+ def save!(**options)
52
53
  perform_validations(options) ? super : raise_validation_error
53
54
  end
54
55
 
@@ -71,7 +72,6 @@ module ActiveRecord
71
72
  alias_method :validate, :valid?
72
73
 
73
74
  private
74
-
75
75
  def default_validation_context
76
76
  new_record? ? :create : :update
77
77
  end
data/lib/active_record.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2018 David Heinemeier Hansson
4
+ # Copyright (c) 2004-2019 David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -35,6 +35,7 @@ require "active_model/attribute_set"
35
35
  module ActiveRecord
36
36
  extend ActiveSupport::Autoload
37
37
 
38
+ autoload :AdvisoryLockBase
38
39
  autoload :Base
39
40
  autoload :Callbacks
40
41
  autoload :Core
@@ -55,7 +56,6 @@ module ActiveRecord
55
56
  autoload :Persistence
56
57
  autoload :QueryCache
57
58
  autoload :Querying
58
- autoload :CollectionCacheKey
59
59
  autoload :ReadonlyAttributes
60
60
  autoload :RecordInvalid, "active_record/validations"
61
61
  autoload :Reflection
@@ -74,6 +74,7 @@ module ActiveRecord
74
74
  autoload :Translation
75
75
  autoload :Validations
76
76
  autoload :SecureToken
77
+ autoload :DatabaseSelector, "active_record/middleware/database_selector"
77
78
 
78
79
  eager_autoload do
79
80
  autoload :ActiveRecordError, "active_record/errors"
@@ -153,6 +154,12 @@ module ActiveRecord
153
154
  end
154
155
  end
155
156
 
157
+ module Middleware
158
+ extend ActiveSupport::Autoload
159
+
160
+ autoload :DatabaseSelector, "active_record/middleware/database_selector"
161
+ end
162
+
156
163
  module Tasks
157
164
  extend ActiveSupport::Autoload
158
165
 
@@ -163,6 +170,7 @@ module ActiveRecord
163
170
  "active_record/tasks/postgresql_database_tasks"
164
171
  end
165
172
 
173
+ autoload :TestDatabases, "active_record/test_databases"
166
174
  autoload :TestFixtures, "active_record/fixtures"
167
175
 
168
176
  def self.eager_load!
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module AliasPredication
5
+ def as(other)
6
+ Nodes::As.new self, Nodes::SqlLiteral.new(other)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Attributes
5
+ class Attribute < Struct.new :relation, :name
6
+ include Arel::Expressions
7
+ include Arel::Predications
8
+ include Arel::AliasPredication
9
+ include Arel::OrderPredications
10
+ include Arel::Math
11
+
12
+ ###
13
+ # Create a node for lowering this attribute
14
+ def lower
15
+ relation.lower self
16
+ end
17
+
18
+ def type_cast_for_database(value)
19
+ relation.type_cast_for_database(name, value)
20
+ end
21
+
22
+ def able_to_type_cast?
23
+ relation.able_to_type_cast?
24
+ end
25
+ end
26
+
27
+ class String < Attribute; end
28
+ class Time < Attribute; end
29
+ class Boolean < Attribute; end
30
+ class Decimal < Attribute; end
31
+ class Float < Attribute; end
32
+ class Integer < Attribute; end
33
+ class Undefined < Attribute; end
34
+ end
35
+
36
+ Attribute = Attributes::Attribute
37
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "arel/attributes/attribute"
4
+
5
+ module Arel # :nodoc: all
6
+ module Attributes
7
+ ###
8
+ # Factory method to wrap a raw database +column+ to an Arel Attribute.
9
+ def self.for(column)
10
+ case column.type
11
+ when :string, :text, :binary then String
12
+ when :integer then Integer
13
+ when :float then Float
14
+ when :decimal then Decimal
15
+ when :date, :datetime, :timestamp, :time then Time
16
+ when :boolean then Boolean
17
+ else
18
+ Undefined
19
+ end
20
+ end
21
+ end
22
+ end