activerecord 6.0.1 → 6.1.7

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1314 -633
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_record/aggregations.rb +5 -6
  6. data/lib/active_record/association_relation.rb +26 -15
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -37
  9. data/lib/active_record/associations/association_scope.rb +19 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +38 -13
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +73 -42
  28. data/lib/active_record/associations/preloader/association.rb +49 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +12 -7
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +119 -12
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +33 -9
  45. data/lib/active_record/autosave_association.rb +56 -41
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +24 -3
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -9
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +145 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +63 -77
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  102. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql_adapter.rb +80 -66
  104. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  105. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  106. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
  107. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  108. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  109. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  110. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
  111. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  112. data/lib/active_record/connection_adapters.rb +52 -0
  113. data/lib/active_record/connection_handling.rb +218 -87
  114. data/lib/active_record/core.rb +269 -68
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  117. data/lib/active_record/database_configurations/database_config.rb +52 -9
  118. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  119. data/lib/active_record/database_configurations/url_config.rb +15 -41
  120. data/lib/active_record/database_configurations.rb +125 -85
  121. data/lib/active_record/delegated_type.rb +209 -0
  122. data/lib/active_record/destroy_association_async_job.rb +36 -0
  123. data/lib/active_record/dynamic_matchers.rb +2 -3
  124. data/lib/active_record/enum.rb +80 -38
  125. data/lib/active_record/errors.rb +47 -12
  126. data/lib/active_record/explain.rb +9 -5
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +10 -17
  129. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  130. data/lib/active_record/fixture_set/render_context.rb +1 -1
  131. data/lib/active_record/fixture_set/table_row.rb +2 -3
  132. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  133. data/lib/active_record/fixtures.rb +58 -12
  134. data/lib/active_record/gem_version.rb +2 -2
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +42 -9
  137. data/lib/active_record/integration.rb +3 -5
  138. data/lib/active_record/internal_metadata.rb +18 -7
  139. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  140. data/lib/active_record/locking/optimistic.rb +33 -18
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +28 -9
  143. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  144. data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
  145. data/lib/active_record/middleware/database_selector.rb +4 -2
  146. data/lib/active_record/migration/command_recorder.rb +53 -45
  147. data/lib/active_record/migration/compatibility.rb +75 -21
  148. data/lib/active_record/migration/join_table.rb +0 -1
  149. data/lib/active_record/migration.rb +115 -85
  150. data/lib/active_record/model_schema.rb +117 -15
  151. data/lib/active_record/nested_attributes.rb +2 -5
  152. data/lib/active_record/no_touching.rb +1 -1
  153. data/lib/active_record/null_relation.rb +0 -1
  154. data/lib/active_record/persistence.rb +50 -46
  155. data/lib/active_record/query_cache.rb +15 -5
  156. data/lib/active_record/querying.rb +12 -7
  157. data/lib/active_record/railtie.rb +65 -45
  158. data/lib/active_record/railties/console_sandbox.rb +2 -4
  159. data/lib/active_record/railties/databases.rake +280 -99
  160. data/lib/active_record/readonly_attributes.rb +4 -0
  161. data/lib/active_record/reflection.rb +77 -63
  162. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  163. data/lib/active_record/relation/batches.rb +38 -32
  164. data/lib/active_record/relation/calculations.rb +106 -45
  165. data/lib/active_record/relation/delegation.rb +9 -7
  166. data/lib/active_record/relation/finder_methods.rb +45 -16
  167. data/lib/active_record/relation/from_clause.rb +5 -1
  168. data/lib/active_record/relation/merger.rb +27 -26
  169. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  170. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  171. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  172. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  173. data/lib/active_record/relation/predicate_builder.rb +59 -40
  174. data/lib/active_record/relation/query_methods.rb +339 -188
  175. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  176. data/lib/active_record/relation/spawn_methods.rb +8 -8
  177. data/lib/active_record/relation/where_clause.rb +111 -62
  178. data/lib/active_record/relation.rb +116 -83
  179. data/lib/active_record/result.rb +41 -34
  180. data/lib/active_record/runtime_registry.rb +2 -2
  181. data/lib/active_record/sanitization.rb +6 -17
  182. data/lib/active_record/schema_dumper.rb +34 -4
  183. data/lib/active_record/schema_migration.rb +2 -8
  184. data/lib/active_record/scoping/default.rb +1 -4
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/scoping.rb +0 -1
  187. data/lib/active_record/secure_token.rb +16 -8
  188. data/lib/active_record/serialization.rb +5 -3
  189. data/lib/active_record/signed_id.rb +116 -0
  190. data/lib/active_record/statement_cache.rb +20 -4
  191. data/lib/active_record/store.rb +9 -4
  192. data/lib/active_record/suppressor.rb +2 -2
  193. data/lib/active_record/table_metadata.rb +42 -36
  194. data/lib/active_record/tasks/database_tasks.rb +140 -113
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  197. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  198. data/lib/active_record/test_databases.rb +5 -4
  199. data/lib/active_record/test_fixtures.rb +87 -20
  200. data/lib/active_record/timestamp.rb +4 -7
  201. data/lib/active_record/touch_later.rb +20 -21
  202. data/lib/active_record/transactions.rb +25 -72
  203. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  204. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  205. data/lib/active_record/type/serialized.rb +6 -3
  206. data/lib/active_record/type/time.rb +10 -0
  207. data/lib/active_record/type/type_map.rb +0 -1
  208. data/lib/active_record/type/unsigned_integer.rb +0 -1
  209. data/lib/active_record/type.rb +8 -2
  210. data/lib/active_record/type_caster/connection.rb +0 -1
  211. data/lib/active_record/type_caster/map.rb +8 -5
  212. data/lib/active_record/validations/associated.rb +1 -2
  213. data/lib/active_record/validations/numericality.rb +35 -0
  214. data/lib/active_record/validations/uniqueness.rb +24 -4
  215. data/lib/active_record/validations.rb +3 -3
  216. data/lib/active_record.rb +7 -13
  217. data/lib/arel/attributes/attribute.rb +4 -0
  218. data/lib/arel/collectors/bind.rb +5 -0
  219. data/lib/arel/collectors/composite.rb +8 -0
  220. data/lib/arel/collectors/sql_string.rb +7 -0
  221. data/lib/arel/collectors/substitute_binds.rb +7 -0
  222. data/lib/arel/nodes/binary.rb +82 -8
  223. data/lib/arel/nodes/bind_param.rb +8 -0
  224. data/lib/arel/nodes/casted.rb +21 -9
  225. data/lib/arel/nodes/equality.rb +6 -9
  226. data/lib/arel/nodes/grouping.rb +3 -0
  227. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  228. data/lib/arel/nodes/in.rb +8 -1
  229. data/lib/arel/nodes/infix_operation.rb +13 -1
  230. data/lib/arel/nodes/join_source.rb +1 -1
  231. data/lib/arel/nodes/node.rb +7 -6
  232. data/lib/arel/nodes/ordering.rb +27 -0
  233. data/lib/arel/nodes/sql_literal.rb +3 -0
  234. data/lib/arel/nodes/table_alias.rb +7 -3
  235. data/lib/arel/nodes/unary.rb +0 -1
  236. data/lib/arel/nodes.rb +3 -1
  237. data/lib/arel/predications.rb +17 -24
  238. data/lib/arel/select_manager.rb +1 -2
  239. data/lib/arel/table.rb +13 -5
  240. data/lib/arel/visitors/dot.rb +14 -3
  241. data/lib/arel/visitors/mysql.rb +11 -1
  242. data/lib/arel/visitors/postgresql.rb +15 -5
  243. data/lib/arel/visitors/sqlite.rb +0 -1
  244. data/lib/arel/visitors/to_sql.rb +89 -79
  245. data/lib/arel/visitors/visitor.rb +0 -1
  246. data/lib/arel/visitors.rb +0 -7
  247. data/lib/arel.rb +5 -9
  248. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  249. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  250. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  251. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  252. data/lib/rails/generators/active_record/migration.rb +6 -2
  253. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  254. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  255. metadata +30 -29
  256. data/lib/active_record/attribute_decorators.rb +0 -90
  257. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  258. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  259. data/lib/active_record/define_callbacks.rb +0 -22
  260. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  261. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  262. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  263. data/lib/arel/attributes.rb +0 -22
  264. data/lib/arel/visitors/depth_first.rb +0 -204
  265. data/lib/arel/visitors/ibm_db.rb +0 -34
  266. data/lib/arel/visitors/informix.rb +0 -62
  267. data/lib/arel/visitors/mssql.rb +0 -157
  268. data/lib/arel/visitors/oracle.rb +0 -159
  269. data/lib/arel/visitors/oracle12.rb +0 -66
  270. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -10,9 +10,6 @@ module ActiveRecord
10
10
  included do
11
11
  define_callbacks :commit, :rollback,
12
12
  :before_commit,
13
- :before_commit_without_transaction_enrollment,
14
- :commit_without_transaction_enrollment,
15
- :rollback_without_transaction_enrollment,
16
13
  scope: [:kind, :name]
17
14
  end
18
15
 
@@ -164,13 +161,13 @@ module ActiveRecord
164
161
  # end
165
162
  # end
166
163
  #
167
- # only "Kotori" is created. This works on MySQL and PostgreSQL. SQLite3 version >= '3.6.8' also supports it.
164
+ # only "Kotori" is created.
168
165
  #
169
166
  # Most databases don't support true nested transactions. At the time of
170
167
  # writing, the only database that we're aware of that supports true nested
171
168
  # transactions, is MS-SQL. Because of this, Active Record emulates nested
172
- # transactions by using savepoints on MySQL and PostgreSQL. See
173
- # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
169
+ # transactions by using savepoints. See
170
+ # https://dev.mysql.com/doc/refman/en/savepoint.html
174
171
  # for more information about savepoints.
175
172
  #
176
173
  # === \Callbacks
@@ -208,8 +205,8 @@ module ActiveRecord
208
205
  # Note that "TRUNCATE" is also a MySQL DDL statement!
209
206
  module ClassMethods
210
207
  # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
211
- def transaction(options = {}, &block)
212
- connection.transaction(options, &block)
208
+ def transaction(**options, &block)
209
+ connection.transaction(**options, &block)
213
210
  end
214
211
 
215
212
  def before_commit(*args, &block) # :nodoc:
@@ -266,23 +263,7 @@ module ActiveRecord
266
263
  set_callback(:rollback, :after, *args, &block)
267
264
  end
268
265
 
269
- def before_commit_without_transaction_enrollment(*args, &block) # :nodoc:
270
- set_options_for_callbacks!(args)
271
- set_callback(:before_commit_without_transaction_enrollment, :before, *args, &block)
272
- end
273
-
274
- def after_commit_without_transaction_enrollment(*args, &block) # :nodoc:
275
- set_options_for_callbacks!(args)
276
- set_callback(:commit_without_transaction_enrollment, :after, *args, &block)
277
- end
278
-
279
- def after_rollback_without_transaction_enrollment(*args, &block) # :nodoc:
280
- set_options_for_callbacks!(args)
281
- set_callback(:rollback_without_transaction_enrollment, :after, *args, &block)
282
- end
283
-
284
266
  private
285
-
286
267
  def set_options_for_callbacks!(args, enforced_options = {})
287
268
  options = args.extract_options!.merge!(enforced_options)
288
269
  args << options
@@ -290,8 +271,10 @@ module ActiveRecord
290
271
  if options[:on]
291
272
  fire_on = Array(options[:on])
292
273
  assert_valid_transaction_action(fire_on)
293
- options[:if] = Array(options[:if])
294
- options[:if].unshift(-> { transaction_include_any_action?(fire_on) })
274
+ options[:if] = [
275
+ -> { transaction_include_any_action?(fire_on) },
276
+ *options[:if]
277
+ ]
295
278
  end
296
279
  end
297
280
 
@@ -303,28 +286,27 @@ module ActiveRecord
303
286
  end
304
287
 
305
288
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
306
- def transaction(options = {}, &block)
307
- self.class.transaction(options, &block)
289
+ def transaction(**options, &block)
290
+ self.class.transaction(**options, &block)
308
291
  end
309
292
 
310
293
  def destroy #:nodoc:
311
294
  with_transaction_returning_status { super }
312
295
  end
313
296
 
314
- def save(*) #:nodoc:
297
+ def save(**) #:nodoc:
315
298
  with_transaction_returning_status { super }
316
299
  end
317
300
 
318
- def save!(*) #:nodoc:
301
+ def save!(**) #:nodoc:
319
302
  with_transaction_returning_status { super }
320
303
  end
321
304
 
322
- def touch(*) #:nodoc:
305
+ def touch(*, **) #:nodoc:
323
306
  with_transaction_returning_status { super }
324
307
  end
325
308
 
326
309
  def before_committed! # :nodoc:
327
- _run_before_commit_without_transaction_enrollment_callbacks
328
310
  _run_before_commit_callbacks
329
311
  end
330
312
 
@@ -336,11 +318,10 @@ module ActiveRecord
336
318
  force_clear_transaction_record_state
337
319
  if should_run_callbacks
338
320
  @_committed_already_called = true
339
- _run_commit_without_transaction_enrollment_callbacks
340
321
  _run_commit_callbacks
341
322
  end
342
323
  ensure
343
- @_committed_already_called = false
324
+ @_committed_already_called = @_trigger_update_callback = @_trigger_destroy_callback = false
344
325
  end
345
326
 
346
327
  # Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
@@ -348,11 +329,11 @@ module ActiveRecord
348
329
  def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
349
330
  if should_run_callbacks
350
331
  _run_rollback_callbacks
351
- _run_rollback_without_transaction_enrollment_callbacks
352
332
  end
353
333
  ensure
354
334
  restore_transaction_record_state(force_restore_state)
355
335
  clear_transaction_record_state
336
+ @_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state
356
337
  end
357
338
 
358
339
  # Executes +method+ within a transaction and captures its return value as a
@@ -363,13 +344,11 @@ module ActiveRecord
363
344
  # instance.
364
345
  def with_transaction_returning_status
365
346
  status = nil
366
- self.class.transaction do
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
347
+ connection = self.class.connection
348
+ ensure_finalize = !connection.transaction_open?
349
+
350
+ connection.transaction do
351
+ add_to_transaction(ensure_finalize || has_transactional_callbacks?)
373
352
  remember_transaction_record_state
374
353
 
375
354
  status = yield
@@ -391,6 +370,7 @@ module ActiveRecord
391
370
  @_start_transaction_state ||= {
392
371
  id: id,
393
372
  new_record: @new_record,
373
+ previously_new_record: @previously_new_record,
394
374
  destroyed: @destroyed,
395
375
  attributes: @attributes,
396
376
  frozen?: frozen?,
@@ -415,7 +395,6 @@ module ActiveRecord
415
395
  # Force to clear the transaction record state.
416
396
  def force_clear_transaction_record_state
417
397
  @_start_transaction_state = nil
418
- @transaction_state = nil
419
398
  end
420
399
 
421
400
  # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
@@ -423,6 +402,7 @@ module ActiveRecord
423
402
  if restore_state = @_start_transaction_state
424
403
  if force_restore_state || restore_state[:level] <= 1
425
404
  @new_record = restore_state[:new_record]
405
+ @previously_new_record = restore_state[:previously_new_record]
426
406
  @destroyed = restore_state[:destroyed]
427
407
  @attributes = restore_state[:attributes].map do |attr|
428
408
  value = @attributes.fetch_value(attr.name)
@@ -455,39 +435,12 @@ module ActiveRecord
455
435
 
456
436
  # Add the record to the current transaction so that the #after_rollback and #after_commit
457
437
  # callbacks can be called.
458
- def add_to_transaction
459
- self.class.connection.add_transaction_record(self)
438
+ def add_to_transaction(ensure_finalize = true)
439
+ self.class.connection.add_transaction_record(self, ensure_finalize)
460
440
  end
461
441
 
462
442
  def has_transactional_callbacks?
463
443
  !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
464
444
  end
465
-
466
- # Updates the attributes on this particular Active Record object so that
467
- # if it's associated with a transaction, then the state of the Active Record
468
- # object will be updated to reflect the current state of the transaction.
469
- #
470
- # The <tt>@transaction_state</tt> variable stores the states of the associated
471
- # transaction. This relies on the fact that a transaction can only be in
472
- # one rollback or commit (otherwise a list of states would be required).
473
- # Each Active Record object inside of a transaction carries that transaction's
474
- # TransactionState.
475
- #
476
- # This method checks to see if the ActiveRecord object's state reflects
477
- # the TransactionState, and rolls back or commits the Active Record object
478
- # as appropriate.
479
- def sync_with_transaction_state
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
490
- end
491
- end
492
445
  end
493
446
  end
@@ -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
@@ -53,7 +52,6 @@ module ActiveRecord
53
52
  end
54
53
 
55
54
  protected
56
-
57
55
  attr_reader :name, :block, :adapter, :override
58
56
 
59
57
  def priority
@@ -72,7 +70,6 @@ module ActiveRecord
72
70
  end
73
71
 
74
72
  private
75
-
76
73
  def matches_adapter?(adapter: nil, **)
77
74
  (self.adapter.nil? || adapter == self.adapter)
78
75
  end
@@ -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,15 +56,18 @@ 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
63
62
 
64
63
  def encoded(value)
65
- unless default_value?(value)
66
- coder.dump(value)
64
+ return if default_value?(value)
65
+ payload = coder.dump(value)
66
+ if payload && binary? && payload.encoding != Encoding::BINARY
67
+ payload = payload.dup if payload.frozen?
68
+ payload.force_encoding(Encoding::BINARY)
67
69
  end
70
+ payload
68
71
  end
69
72
  end
70
73
  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
@@ -46,10 +46,14 @@ module ActiveRecord
46
46
  @default_value ||= Value.new
47
47
  end
48
48
 
49
- private
49
+ def adapter_name_from(model) # :nodoc:
50
+ # TODO: this shouldn't depend on a connection to the database
51
+ model.connection.adapter_name.downcase.to_sym
52
+ end
50
53
 
54
+ private
51
55
  def current_adapter_name
52
- ActiveRecord::Base.connection.adapter_name.downcase.to_sym
56
+ adapter_name_from(ActiveRecord::Base)
53
57
  end
54
58
  end
55
59
 
@@ -59,6 +63,7 @@ module ActiveRecord
59
63
  Decimal = ActiveModel::Type::Decimal
60
64
  Float = ActiveModel::Type::Float
61
65
  Integer = ActiveModel::Type::Integer
66
+ ImmutableString = ActiveModel::Type::ImmutableString
62
67
  String = ActiveModel::Type::String
63
68
  Value = ActiveModel::Type::Value
64
69
 
@@ -70,6 +75,7 @@ module ActiveRecord
70
75
  register(:decimal, Type::Decimal, override: false)
71
76
  register(:float, Type::Float, override: false)
72
77
  register(:integer, Type::Integer, override: false)
78
+ register(:immutable_string, Type::ImmutableString, override: false)
73
79
  register(:json, Type::Json, override: false)
74
80
  register(:string, Type::String, override: false)
75
81
  register(:text, Type::Text, override: false)
@@ -9,7 +9,6 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  def type_cast_for_database(attr_name, value)
12
- return value if value.is_a?(Arel::Nodes::BindParam)
13
12
  type = type_for_attribute(attr_name)
14
13
  type.serialize(value)
15
14
  end
@@ -3,18 +3,21 @@
3
3
  module ActiveRecord
4
4
  module TypeCaster
5
5
  class Map # :nodoc:
6
- def initialize(types)
7
- @types = types
6
+ def initialize(klass)
7
+ @klass = klass
8
8
  end
9
9
 
10
10
  def type_cast_for_database(attr_name, value)
11
- return value if value.is_a?(Arel::Nodes::BindParam)
12
- type = types.type_for_attribute(attr_name)
11
+ type = type_for_attribute(attr_name)
13
12
  type.serialize(value)
14
13
  end
15
14
 
15
+ def type_for_attribute(name)
16
+ klass.type_for_attribute(name)
17
+ end
18
+
16
19
  private
17
- attr_reader :types
20
+ attr_reader :klass
18
21
  end
19
22
  end
20
23
  end
@@ -5,12 +5,11 @@ module ActiveRecord
5
5
  class AssociatedValidator < ActiveModel::EachValidator #:nodoc:
6
6
  def validate_each(record, attribute, value)
7
7
  if Array(value).reject { |r| valid_object?(r) }.any?
8
- record.errors.add(attribute, :invalid, options.merge(value: value))
8
+ record.errors.add(attribute, :invalid, **options.merge(value: value))
9
9
  end
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
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Validations
5
+ class NumericalityValidator < ActiveModel::Validations::NumericalityValidator # :nodoc:
6
+ def validate_each(record, attribute, value, precision: nil, scale: nil)
7
+ precision = [column_precision_for(record, attribute) || Float::DIG, Float::DIG].min
8
+ scale = column_scale_for(record, attribute)
9
+ super(record, attribute, value, precision: precision, scale: scale)
10
+ end
11
+
12
+ private
13
+ def column_precision_for(record, attribute)
14
+ record.class.type_for_attribute(attribute.to_s)&.precision
15
+ end
16
+
17
+ def column_scale_for(record, attribute)
18
+ record.class.type_for_attribute(attribute.to_s)&.scale
19
+ end
20
+ end
21
+
22
+ module ClassMethods
23
+ # Validates whether the value of the specified attribute is numeric by
24
+ # trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
25
+ # is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\z/</tt>
26
+ # (if <tt>only_integer</tt> is set to +true+). Kernel.Float precision
27
+ # defaults to the column's precision value or 15.
28
+ #
29
+ # See ActiveModel::Validations::HelperMethods.validates_numericality_of for more information.
30
+ def validates_numericality_of(*attr_names)
31
+ validates_with NumericalityValidator, _merge_attributes(attr_names)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -29,13 +29,22 @@ module ActiveRecord
29
29
  end
30
30
  end
31
31
  relation = scope_relation(record, relation)
32
- relation = relation.merge(options[:conditions]) if options[:conditions]
32
+
33
+ if options[:conditions]
34
+ conditions = options[:conditions]
35
+
36
+ relation = if conditions.arity.zero?
37
+ relation.instance_exec(&conditions)
38
+ else
39
+ relation.instance_exec(record, &conditions)
40
+ end
41
+ end
33
42
 
34
43
  if relation.exists?
35
44
  error_options = options.except(:case_sensitive, :scope, :conditions)
36
45
  error_options[:value] = value
37
46
 
38
- record.errors.add(attribute, :taken, error_options)
47
+ record.errors.add(attribute, :taken, **error_options)
39
48
  end
40
49
  end
41
50
 
@@ -61,7 +70,7 @@ module ActiveRecord
61
70
  return relation.none! if bind.unboundable?
62
71
 
63
72
  if !options.key?(:case_sensitive) || bind.nil?
64
- klass.connection.default_uniqueness_comparison(attr, bind, klass)
73
+ klass.connection.default_uniqueness_comparison(attr, bind)
65
74
  elsif options[:case_sensitive]
66
75
  klass.connection.case_sensitive_comparison(attr, bind)
67
76
  else
@@ -78,7 +87,7 @@ module ActiveRecord
78
87
  scope_value = if record.class._reflect_on_association(scope_item)
79
88
  record.association(scope_item).reader
80
89
  else
81
- record._read_attribute(scope_item)
90
+ record.read_attribute(scope_item)
82
91
  end
83
92
  relation = relation.where(scope_item => scope_value)
84
93
  end
@@ -126,6 +135,17 @@ module ActiveRecord
126
135
  # validates_uniqueness_of :title, conditions: -> { where.not(status: 'archived') }
127
136
  # end
128
137
  #
138
+ # To build conditions based on the record's state, define the conditions
139
+ # callable with a parameter, which will be the record itself. This
140
+ # example validates the title is unique for the year of publication:
141
+ #
142
+ # class Article < ActiveRecord::Base
143
+ # validates_uniqueness_of :title, conditions: ->(article) {
144
+ # published_at = article.published_at
145
+ # where(published_at: published_at.beginning_of_year..published_at.end_of_year)
146
+ # }
147
+ # end
148
+ #
129
149
  # When the record is created, a check is performed to make sure that no
130
150
  # record exists in the database with the given value for the specified
131
151
  # attribute (that maps to a column). When the record is updated,
@@ -43,13 +43,13 @@ module ActiveRecord
43
43
  # The validation context can be changed by passing <tt>context: context</tt>.
44
44
  # The regular {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] method is replaced
45
45
  # with this when the validations module is mixed in, which it is by default.
46
- def save(options = {})
46
+ def save(**options)
47
47
  perform_validations(options) ? super : false
48
48
  end
49
49
 
50
50
  # Attempts to save the record just like {ActiveRecord::Base#save}[rdoc-ref:Base#save] but
51
51
  # will raise an ActiveRecord::RecordInvalid exception instead of returning +false+ if the record is not valid.
52
- def save!(options = {})
52
+ def save!(**options)
53
53
  perform_validations(options) ? super : raise_validation_error
54
54
  end
55
55
 
@@ -72,7 +72,6 @@ module ActiveRecord
72
72
  alias_method :validate, :valid?
73
73
 
74
74
  private
75
-
76
75
  def default_validation_context
77
76
  new_record? ? :create : :update
78
77
  end
@@ -92,3 +91,4 @@ require "active_record/validations/uniqueness"
92
91
  require "active_record/validations/presence"
93
92
  require "active_record/validations/absence"
94
93
  require "active_record/validations/length"
94
+ require "active_record/validations/numericality"
data/lib/active_record.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2019 David Heinemeier Hansson
4
+ # Copyright (c) 2004-2022 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
@@ -31,6 +31,7 @@ require "yaml"
31
31
 
32
32
  require "active_record/version"
33
33
  require "active_model/attribute_set"
34
+ require "active_record/errors"
34
35
 
35
36
  module ActiveRecord
36
37
  extend ActiveSupport::Autoload
@@ -41,6 +42,7 @@ module ActiveRecord
41
42
  autoload :ConnectionHandling
42
43
  autoload :CounterCache
43
44
  autoload :DynamicMatchers
45
+ autoload :DelegatedType
44
46
  autoload :Enum
45
47
  autoload :InternalMetadata
46
48
  autoload :Explain
@@ -67,18 +69,17 @@ module ActiveRecord
67
69
  autoload :Serialization
68
70
  autoload :StatementCache
69
71
  autoload :Store
72
+ autoload :SignedId
70
73
  autoload :Suppressor
71
74
  autoload :Timestamp
72
75
  autoload :Transactions
73
76
  autoload :Translation
74
77
  autoload :Validations
75
78
  autoload :SecureToken
76
- autoload :DatabaseSelector, "active_record/middleware/database_selector"
79
+ autoload :DestroyAssociationAsyncJob
77
80
 
78
81
  eager_autoload do
79
- autoload :ActiveRecordError, "active_record/errors"
80
- autoload :ConnectionNotEstablished, "active_record/errors"
81
- autoload :ConnectionAdapters, "active_record/connection_adapters/abstract_adapter"
82
+ autoload :ConnectionAdapters
82
83
 
83
84
  autoload :Aggregations
84
85
  autoload :Associations
@@ -136,14 +137,6 @@ module ActiveRecord
136
137
  end
137
138
  end
138
139
 
139
- module ConnectionAdapters
140
- extend ActiveSupport::Autoload
141
-
142
- eager_autoload do
143
- autoload :AbstractAdapter
144
- end
145
- end
146
-
147
140
  module Scoping
148
141
  extend ActiveSupport::Autoload
149
142
 
@@ -193,3 +186,4 @@ end
193
186
  YAML.load_tags["!ruby/object:ActiveRecord::AttributeSet"] = "ActiveModel::AttributeSet"
194
187
  YAML.load_tags["!ruby/object:ActiveRecord::Attribute::FromDatabase"] = "ActiveModel::Attribute::FromDatabase"
195
188
  YAML.load_tags["!ruby/object:ActiveRecord::LazyAttributeHash"] = "ActiveModel::LazyAttributeHash"
189
+ YAML.load_tags["!ruby/object:ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString"] = "ActiveRecord::Type::String"
@@ -9,6 +9,10 @@ module Arel # :nodoc: all
9
9
  include Arel::OrderPredications
10
10
  include Arel::Math
11
11
 
12
+ def type_caster
13
+ relation.type_for_attribute(name)
14
+ end
15
+
12
16
  ###
13
17
  # Create a node for lowering this attribute
14
18
  def lower
@@ -16,6 +16,11 @@ module Arel # :nodoc: all
16
16
  self
17
17
  end
18
18
 
19
+ def add_binds(binds, proc_for_binds = nil)
20
+ @binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
21
+ self
22
+ end
23
+
19
24
  def value
20
25
  @binds
21
26
  end
@@ -3,6 +3,8 @@
3
3
  module Arel # :nodoc: all
4
4
  module Collectors
5
5
  class Composite
6
+ attr_accessor :preparable
7
+
6
8
  def initialize(left, right)
7
9
  @left = left
8
10
  @right = right
@@ -20,6 +22,12 @@ module Arel # :nodoc: all
20
22
  self
21
23
  end
22
24
 
25
+ def add_binds(binds, proc_for_binds = nil, &block)
26
+ left.add_binds(binds, proc_for_binds, &block)
27
+ right.add_binds(binds, proc_for_binds, &block)
28
+ self
29
+ end
30
+
23
31
  def value
24
32
  [left.value, right.value]
25
33
  end
@@ -5,6 +5,8 @@ require "arel/collectors/plain_string"
5
5
  module Arel # :nodoc: all
6
6
  module Collectors
7
7
  class SQLString < PlainString
8
+ attr_accessor :preparable
9
+
8
10
  def initialize(*)
9
11
  super
10
12
  @bind_index = 1
@@ -15,6 +17,11 @@ module Arel # :nodoc: all
15
17
  @bind_index += 1
16
18
  self
17
19
  end
20
+
21
+ def add_binds(binds, proc_for_binds = nil, &block)
22
+ self << (@bind_index...@bind_index += binds.size).map(&block).join(", ")
23
+ self
24
+ end
18
25
  end
19
26
  end
20
27
  end