activerecord 6.0.5.1 → 6.1.0.rc1

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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +764 -916
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +22 -14
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +39 -27
  9. data/lib/active_record/associations/association_scope.rb +11 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  12. data/lib/active_record/associations/builder/association.rb +9 -3
  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 -1
  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 +19 -13
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  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 +29 -14
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +13 -5
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +114 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +4 -4
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +52 -48
  43. data/lib/active_record/attributes.rb +27 -7
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +32 -22
  47. data/lib/active_record/coders/yaml_column.rb +2 -14
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -10
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  88. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  91. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  93. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  94. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  95. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
  96. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  98. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  99. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  100. data/lib/active_record/connection_adapters.rb +50 -0
  101. data/lib/active_record/connection_handling.rb +210 -71
  102. data/lib/active_record/core.rb +214 -58
  103. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  104. data/lib/active_record/database_configurations/database_config.rb +52 -9
  105. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  106. data/lib/active_record/database_configurations/url_config.rb +15 -40
  107. data/lib/active_record/database_configurations.rb +124 -85
  108. data/lib/active_record/delegated_type.rb +209 -0
  109. data/lib/active_record/destroy_association_async_job.rb +36 -0
  110. data/lib/active_record/enum.rb +33 -23
  111. data/lib/active_record/errors.rb +47 -12
  112. data/lib/active_record/explain.rb +9 -4
  113. data/lib/active_record/explain_subscriber.rb +1 -1
  114. data/lib/active_record/fixture_set/file.rb +10 -17
  115. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  116. data/lib/active_record/fixture_set/render_context.rb +1 -1
  117. data/lib/active_record/fixture_set/table_row.rb +2 -2
  118. data/lib/active_record/fixtures.rb +54 -8
  119. data/lib/active_record/gem_version.rb +3 -3
  120. data/lib/active_record/inheritance.rb +40 -18
  121. data/lib/active_record/insert_all.rb +32 -5
  122. data/lib/active_record/integration.rb +3 -5
  123. data/lib/active_record/internal_metadata.rb +15 -4
  124. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  125. data/lib/active_record/locking/optimistic.rb +13 -16
  126. data/lib/active_record/locking/pessimistic.rb +6 -2
  127. data/lib/active_record/log_subscriber.rb +26 -8
  128. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  129. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/migration/command_recorder.rb +47 -27
  132. data/lib/active_record/migration/compatibility.rb +67 -17
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/model_schema.rb +88 -42
  135. data/lib/active_record/nested_attributes.rb +2 -3
  136. data/lib/active_record/no_touching.rb +1 -1
  137. data/lib/active_record/persistence.rb +50 -45
  138. data/lib/active_record/query_cache.rb +15 -5
  139. data/lib/active_record/querying.rb +11 -6
  140. data/lib/active_record/railtie.rb +61 -59
  141. data/lib/active_record/railties/databases.rake +253 -98
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +59 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +100 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +57 -33
  155. data/lib/active_record/relation/query_methods.rb +319 -196
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +6 -5
  158. data/lib/active_record/relation/where_clause.rb +104 -57
  159. data/lib/active_record/relation.rb +90 -64
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +0 -4
  165. data/lib/active_record/scoping/named.rb +1 -17
  166. data/lib/active_record/secure_token.rb +16 -8
  167. data/lib/active_record/serialization.rb +5 -3
  168. data/lib/active_record/signed_id.rb +116 -0
  169. data/lib/active_record/statement_cache.rb +20 -4
  170. data/lib/active_record/store.rb +2 -2
  171. data/lib/active_record/suppressor.rb +2 -2
  172. data/lib/active_record/table_metadata.rb +36 -52
  173. data/lib/active_record/tasks/database_tasks.rb +139 -113
  174. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  175. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  176. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  177. data/lib/active_record/test_databases.rb +5 -4
  178. data/lib/active_record/test_fixtures.rb +36 -33
  179. data/lib/active_record/timestamp.rb +4 -6
  180. data/lib/active_record/touch_later.rb +21 -21
  181. data/lib/active_record/transactions.rb +15 -64
  182. data/lib/active_record/type/serialized.rb +6 -2
  183. data/lib/active_record/type.rb +8 -1
  184. data/lib/active_record/type_caster/connection.rb +0 -1
  185. data/lib/active_record/type_caster/map.rb +8 -5
  186. data/lib/active_record/validations/associated.rb +1 -1
  187. data/lib/active_record/validations/numericality.rb +35 -0
  188. data/lib/active_record/validations/uniqueness.rb +24 -4
  189. data/lib/active_record/validations.rb +1 -0
  190. data/lib/active_record.rb +7 -14
  191. data/lib/arel/attributes/attribute.rb +4 -0
  192. data/lib/arel/collectors/bind.rb +5 -0
  193. data/lib/arel/collectors/composite.rb +8 -0
  194. data/lib/arel/collectors/sql_string.rb +7 -0
  195. data/lib/arel/collectors/substitute_binds.rb +7 -0
  196. data/lib/arel/nodes/binary.rb +82 -8
  197. data/lib/arel/nodes/bind_param.rb +8 -0
  198. data/lib/arel/nodes/casted.rb +21 -9
  199. data/lib/arel/nodes/equality.rb +6 -9
  200. data/lib/arel/nodes/grouping.rb +3 -0
  201. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  202. data/lib/arel/nodes/in.rb +8 -1
  203. data/lib/arel/nodes/infix_operation.rb +13 -1
  204. data/lib/arel/nodes/join_source.rb +1 -1
  205. data/lib/arel/nodes/node.rb +7 -6
  206. data/lib/arel/nodes/ordering.rb +27 -0
  207. data/lib/arel/nodes/sql_literal.rb +3 -0
  208. data/lib/arel/nodes/table_alias.rb +7 -3
  209. data/lib/arel/nodes/unary.rb +0 -1
  210. data/lib/arel/nodes.rb +3 -1
  211. data/lib/arel/predications.rb +12 -18
  212. data/lib/arel/select_manager.rb +1 -2
  213. data/lib/arel/table.rb +13 -5
  214. data/lib/arel/visitors/dot.rb +14 -2
  215. data/lib/arel/visitors/mysql.rb +11 -1
  216. data/lib/arel/visitors/postgresql.rb +15 -4
  217. data/lib/arel/visitors/to_sql.rb +89 -78
  218. data/lib/arel/visitors.rb +0 -7
  219. data/lib/arel.rb +5 -13
  220. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  221. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  222. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  223. data/lib/rails/generators/active_record/migration.rb +6 -1
  224. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  225. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  226. metadata +30 -32
  227. data/lib/active_record/advisory_lock_base.rb +0 -18
  228. data/lib/active_record/attribute_decorators.rb +0 -88
  229. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  230. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  231. data/lib/active_record/define_callbacks.rb +0 -22
  232. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  233. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  234. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  235. data/lib/arel/attributes.rb +0 -22
  236. data/lib/arel/visitors/depth_first.rb +0 -203
  237. data/lib/arel/visitors/ibm_db.rb +0 -34
  238. data/lib/arel/visitors/informix.rb +0 -62
  239. data/lib/arel/visitors/mssql.rb +0 -156
  240. data/lib/arel/visitors/oracle.rb +0 -158
  241. data/lib/arel/visitors/oracle12.rb +0 -65
  242. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -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
@@ -266,21 +263,6 @@ 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
267
  def set_options_for_callbacks!(args, enforced_options = {})
286
268
  options = args.extract_options!.merge!(enforced_options)
@@ -302,7 +284,7 @@ module ActiveRecord
302
284
  end
303
285
 
304
286
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
305
- def transaction(options = {}, &block)
287
+ def transaction(**options, &block)
306
288
  self.class.transaction(**options, &block)
307
289
  end
308
290
 
@@ -310,11 +292,11 @@ module ActiveRecord
310
292
  with_transaction_returning_status { super }
311
293
  end
312
294
 
313
- def save(*, **) #:nodoc:
295
+ def save(**) #:nodoc:
314
296
  with_transaction_returning_status { super }
315
297
  end
316
298
 
317
- def save!(*, **) #:nodoc:
299
+ def save!(**) #:nodoc:
318
300
  with_transaction_returning_status { super }
319
301
  end
320
302
 
@@ -323,7 +305,6 @@ module ActiveRecord
323
305
  end
324
306
 
325
307
  def before_committed! # :nodoc:
326
- _run_before_commit_without_transaction_enrollment_callbacks
327
308
  _run_before_commit_callbacks
328
309
  end
329
310
 
@@ -335,7 +316,6 @@ module ActiveRecord
335
316
  force_clear_transaction_record_state
336
317
  if should_run_callbacks
337
318
  @_committed_already_called = true
338
- _run_commit_without_transaction_enrollment_callbacks
339
319
  _run_commit_callbacks
340
320
  end
341
321
  ensure
@@ -347,7 +327,6 @@ module ActiveRecord
347
327
  def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
348
328
  if should_run_callbacks
349
329
  _run_rollback_callbacks
350
- _run_rollback_without_transaction_enrollment_callbacks
351
330
  end
352
331
  ensure
353
332
  restore_transaction_record_state(force_restore_state)
@@ -363,13 +342,11 @@ module ActiveRecord
363
342
  # instance.
364
343
  def with_transaction_returning_status
365
344
  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
345
+ connection = self.class.connection
346
+ ensure_finalize = !connection.transaction_open?
347
+
348
+ connection.transaction do
349
+ add_to_transaction(ensure_finalize || has_transactional_callbacks?)
373
350
  remember_transaction_record_state
374
351
 
375
352
  status = yield
@@ -391,6 +368,7 @@ module ActiveRecord
391
368
  @_start_transaction_state ||= {
392
369
  id: id,
393
370
  new_record: @new_record,
371
+ previously_new_record: @previously_new_record,
394
372
  destroyed: @destroyed,
395
373
  attributes: @attributes,
396
374
  frozen?: frozen?,
@@ -415,7 +393,6 @@ module ActiveRecord
415
393
  # Force to clear the transaction record state.
416
394
  def force_clear_transaction_record_state
417
395
  @_start_transaction_state = nil
418
- @transaction_state = nil
419
396
  end
420
397
 
421
398
  # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
@@ -423,6 +400,7 @@ module ActiveRecord
423
400
  if restore_state = @_start_transaction_state
424
401
  if force_restore_state || restore_state[:level] <= 1
425
402
  @new_record = restore_state[:new_record]
403
+ @previously_new_record = restore_state[:previously_new_record]
426
404
  @destroyed = restore_state[:destroyed]
427
405
  @attributes = restore_state[:attributes].map do |attr|
428
406
  value = @attributes.fetch_value(attr.name)
@@ -455,39 +433,12 @@ module ActiveRecord
455
433
 
456
434
  # Add the record to the current transaction so that the #after_rollback and #after_commit
457
435
  # callbacks can be called.
458
- def add_to_transaction
459
- self.class.connection.add_transaction_record(self)
436
+ def add_to_transaction(ensure_finalize = true)
437
+ self.class.connection.add_transaction_record(self, ensure_finalize)
460
438
  end
461
439
 
462
440
  def has_transactional_callbacks?
463
441
  !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
464
442
  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
443
  end
493
444
  end
@@ -61,9 +61,13 @@ module ActiveRecord
61
61
  end
62
62
 
63
63
  def encoded(value)
64
- unless default_value?(value)
65
- 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)
66
69
  end
70
+ payload
67
71
  end
68
72
  end
69
73
  end
@@ -46,9 +46,14 @@ module ActiveRecord
46
46
  @default_value ||= Value.new
47
47
  end
48
48
 
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
53
+
49
54
  private
50
55
  def current_adapter_name
51
- ActiveRecord::Base.connection.adapter_name.downcase.to_sym
56
+ adapter_name_from(ActiveRecord::Base)
52
57
  end
53
58
  end
54
59
 
@@ -58,6 +63,7 @@ module ActiveRecord
58
63
  Decimal = ActiveModel::Type::Decimal
59
64
  Float = ActiveModel::Type::Float
60
65
  Integer = ActiveModel::Type::Integer
66
+ ImmutableString = ActiveModel::Type::ImmutableString
61
67
  String = ActiveModel::Type::String
62
68
  Value = ActiveModel::Type::Value
63
69
 
@@ -69,6 +75,7 @@ module ActiveRecord
69
75
  register(:decimal, Type::Decimal, override: false)
70
76
  register(:float, Type::Float, override: false)
71
77
  register(:integer, Type::Integer, override: false)
78
+ register(:immutable_string, Type::ImmutableString, override: false)
72
79
  register(:json, Type::Json, override: false)
73
80
  register(:string, Type::String, override: false)
74
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,7 +5,7 @@ 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
 
@@ -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) || BigDecimal.double_fig, BigDecimal.double_fig].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,
@@ -91,3 +91,4 @@ require "active_record/validations/uniqueness"
91
91
  require "active_record/validations/presence"
92
92
  require "active_record/validations/absence"
93
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-2020 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,17 +31,18 @@ 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
37
38
 
38
- autoload :AdvisoryLockBase
39
39
  autoload :Base
40
40
  autoload :Callbacks
41
41
  autoload :Core
42
42
  autoload :ConnectionHandling
43
43
  autoload :CounterCache
44
44
  autoload :DynamicMatchers
45
+ autoload :DelegatedType
45
46
  autoload :Enum
46
47
  autoload :InternalMetadata
47
48
  autoload :Explain
@@ -68,18 +69,17 @@ module ActiveRecord
68
69
  autoload :Serialization
69
70
  autoload :StatementCache
70
71
  autoload :Store
72
+ autoload :SignedId
71
73
  autoload :Suppressor
72
74
  autoload :Timestamp
73
75
  autoload :Transactions
74
76
  autoload :Translation
75
77
  autoload :Validations
76
78
  autoload :SecureToken
77
- autoload :DatabaseSelector, "active_record/middleware/database_selector"
79
+ autoload :DestroyAssociationAsyncJob
78
80
 
79
81
  eager_autoload do
80
- autoload :ActiveRecordError, "active_record/errors"
81
- autoload :ConnectionNotEstablished, "active_record/errors"
82
- autoload :ConnectionAdapters, "active_record/connection_adapters/abstract_adapter"
82
+ autoload :ConnectionAdapters
83
83
 
84
84
  autoload :Aggregations
85
85
  autoload :Associations
@@ -137,14 +137,6 @@ module ActiveRecord
137
137
  end
138
138
  end
139
139
 
140
- module ConnectionAdapters
141
- extend ActiveSupport::Autoload
142
-
143
- eager_autoload do
144
- autoload :AbstractAdapter
145
- end
146
- end
147
-
148
140
  module Scoping
149
141
  extend ActiveSupport::Autoload
150
142
 
@@ -194,3 +186,4 @@ end
194
186
  YAML.load_tags["!ruby/object:ActiveRecord::AttributeSet"] = "ActiveModel::AttributeSet"
195
187
  YAML.load_tags["!ruby/object:ActiveRecord::Attribute::FromDatabase"] = "ActiveModel::Attribute::FromDatabase"
196
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)
20
+ @binds.concat 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, &block)
26
+ left.add_binds(binds, &block)
27
+ right.add_binds(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, &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
@@ -3,6 +3,8 @@
3
3
  module Arel # :nodoc: all
4
4
  module Collectors
5
5
  class SubstituteBinds
6
+ attr_accessor :preparable
7
+
6
8
  def initialize(quoter, delegate_collector)
7
9
  @quoter = quoter
8
10
  @delegate = delegate_collector
@@ -14,9 +16,14 @@ module Arel # :nodoc: all
14
16
  end
15
17
 
16
18
  def add_bind(bind)
19
+ bind = bind.value_for_database if bind.respond_to?(:value_for_database)
17
20
  self << quoter.quote(bind)
18
21
  end
19
22
 
23
+ def add_binds(binds)
24
+ self << binds.map { |bind| quoter.quote(bind) }.join(", ")
25
+ end
26
+
20
27
  def value
21
28
  delegate.value
22
29
  end
@@ -29,18 +29,92 @@ module Arel # :nodoc: all
29
29
  alias :== :eql?
30
30
  end
31
31
 
32
+ module FetchAttribute
33
+ def fetch_attribute
34
+ if left.is_a?(Arel::Attributes::Attribute)
35
+ yield left
36
+ elsif right.is_a?(Arel::Attributes::Attribute)
37
+ yield right
38
+ end
39
+ end
40
+ end
41
+
42
+ class Between < Binary; include FetchAttribute; end
43
+
44
+ class GreaterThan < Binary
45
+ include FetchAttribute
46
+
47
+ def invert
48
+ Arel::Nodes::LessThanOrEqual.new(left, right)
49
+ end
50
+ end
51
+
52
+ class GreaterThanOrEqual < Binary
53
+ include FetchAttribute
54
+
55
+ def invert
56
+ Arel::Nodes::LessThan.new(left, right)
57
+ end
58
+ end
59
+
60
+ class LessThan < Binary
61
+ include FetchAttribute
62
+
63
+ def invert
64
+ Arel::Nodes::GreaterThanOrEqual.new(left, right)
65
+ end
66
+ end
67
+
68
+ class LessThanOrEqual < Binary
69
+ include FetchAttribute
70
+
71
+ def invert
72
+ Arel::Nodes::GreaterThan.new(left, right)
73
+ end
74
+ end
75
+
76
+ class IsDistinctFrom < Binary
77
+ include FetchAttribute
78
+
79
+ def invert
80
+ Arel::Nodes::IsNotDistinctFrom.new(left, right)
81
+ end
82
+ end
83
+
84
+ class IsNotDistinctFrom < Binary
85
+ include FetchAttribute
86
+
87
+ def invert
88
+ Arel::Nodes::IsDistinctFrom.new(left, right)
89
+ end
90
+ end
91
+
92
+ class NotEqual < Binary
93
+ include FetchAttribute
94
+
95
+ def invert
96
+ Arel::Nodes::Equality.new(left, right)
97
+ end
98
+ end
99
+
100
+ class NotIn < Binary
101
+ include FetchAttribute
102
+
103
+ def invert
104
+ Arel::Nodes::In.new(left, right)
105
+ end
106
+ end
107
+
108
+ class Or < Binary
109
+ def fetch_attribute(&block)
110
+ left.fetch_attribute(&block) && right.fetch_attribute(&block)
111
+ end
112
+ end
113
+
32
114
  %w{
33
115
  As
34
116
  Assignment
35
- Between
36
- GreaterThan
37
- GreaterThanOrEqual
38
117
  Join
39
- LessThan
40
- LessThanOrEqual
41
- NotEqual
42
- NotIn
43
- Or
44
118
  Union
45
119
  UnionAll
46
120
  Intersect
@@ -24,6 +24,14 @@ module Arel # :nodoc: all
24
24
  value.nil?
25
25
  end
26
26
 
27
+ def value_before_type_cast
28
+ if value.respond_to?(:value_before_type_cast)
29
+ value.value_before_type_cast
30
+ else
31
+ value
32
+ end
33
+ end
34
+
27
35
  def infinite?
28
36
  value.respond_to?(:infinite?) && value.infinite?
29
37
  end