activerecord 6.0.3.4 → 6.1.2

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

Potentially problematic release.


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

Files changed (245) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +891 -695
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record.rb +7 -14
  6. data/lib/active_record/aggregations.rb +5 -5
  7. data/lib/active_record/association_relation.rb +30 -12
  8. data/lib/active_record/associations.rb +118 -11
  9. data/lib/active_record/associations/alias_tracker.rb +19 -15
  10. data/lib/active_record/associations/association.rb +44 -28
  11. data/lib/active_record/associations/association_scope.rb +19 -15
  12. data/lib/active_record/associations/belongs_to_association.rb +22 -8
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  14. data/lib/active_record/associations/builder/association.rb +32 -5
  15. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  16. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  18. data/lib/active_record/associations/builder/has_many.rb +6 -2
  19. data/lib/active_record/associations/builder/has_one.rb +11 -14
  20. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  21. data/lib/active_record/associations/collection_association.rb +19 -6
  22. data/lib/active_record/associations/collection_proxy.rb +13 -5
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +24 -2
  25. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  26. data/lib/active_record/associations/has_one_association.rb +15 -1
  27. data/lib/active_record/associations/join_dependency.rb +72 -50
  28. data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
  29. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  30. data/lib/active_record/associations/preloader.rb +11 -5
  31. data/lib/active_record/associations/preloader/association.rb +51 -25
  32. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  33. data/lib/active_record/associations/singular_association.rb +1 -1
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/attribute_assignment.rb +10 -8
  36. data/lib/active_record/attribute_methods.rb +64 -54
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  38. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  39. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  40. data/lib/active_record/attribute_methods/query.rb +3 -6
  41. data/lib/active_record/attribute_methods/read.rb +8 -11
  42. data/lib/active_record/attribute_methods/serialization.rb +11 -5
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  44. data/lib/active_record/attribute_methods/write.rb +12 -20
  45. data/lib/active_record/attributes.rb +33 -8
  46. data/lib/active_record/autosave_association.rb +57 -40
  47. data/lib/active_record/base.rb +2 -14
  48. data/lib/active_record/callbacks.rb +152 -22
  49. data/lib/active_record/coders/yaml_column.rb +1 -1
  50. data/lib/active_record/connection_adapters.rb +50 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +191 -134
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +116 -27
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +54 -72
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +133 -96
  64. data/lib/active_record/connection_adapters/column.rb +15 -1
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  67. data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -25
  68. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
  71. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  72. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  73. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +11 -7
  74. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  76. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  77. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +13 -54
  80. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  82. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
  89. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  90. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  91. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  93. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  94. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  95. data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -58
  96. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  97. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  98. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +31 -6
  99. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  100. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  101. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
  103. data/lib/active_record/connection_handling.rb +218 -71
  104. data/lib/active_record/core.rb +245 -61
  105. data/lib/active_record/database_configurations.rb +124 -85
  106. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  107. data/lib/active_record/database_configurations/database_config.rb +52 -9
  108. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  109. data/lib/active_record/database_configurations/url_config.rb +15 -40
  110. data/lib/active_record/delegated_type.rb +209 -0
  111. data/lib/active_record/destroy_association_async_job.rb +36 -0
  112. data/lib/active_record/enum.rb +82 -38
  113. data/lib/active_record/errors.rb +47 -12
  114. data/lib/active_record/explain.rb +9 -4
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +10 -17
  117. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  118. data/lib/active_record/fixture_set/render_context.rb +1 -1
  119. data/lib/active_record/fixture_set/table_row.rb +2 -2
  120. data/lib/active_record/fixtures.rb +58 -9
  121. data/lib/active_record/gem_version.rb +3 -3
  122. data/lib/active_record/inheritance.rb +40 -18
  123. data/lib/active_record/insert_all.rb +35 -6
  124. data/lib/active_record/integration.rb +3 -5
  125. data/lib/active_record/internal_metadata.rb +16 -7
  126. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  127. data/lib/active_record/locking/optimistic.rb +33 -17
  128. data/lib/active_record/locking/pessimistic.rb +6 -2
  129. data/lib/active_record/log_subscriber.rb +27 -8
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/migration/command_recorder.rb +47 -27
  135. data/lib/active_record/migration/compatibility.rb +68 -17
  136. data/lib/active_record/model_schema.rb +117 -13
  137. data/lib/active_record/nested_attributes.rb +2 -3
  138. data/lib/active_record/no_touching.rb +1 -1
  139. data/lib/active_record/persistence.rb +50 -45
  140. data/lib/active_record/query_cache.rb +15 -5
  141. data/lib/active_record/querying.rb +11 -6
  142. data/lib/active_record/railtie.rb +64 -44
  143. data/lib/active_record/railties/console_sandbox.rb +2 -4
  144. data/lib/active_record/railties/databases.rake +276 -99
  145. data/lib/active_record/readonly_attributes.rb +4 -0
  146. data/lib/active_record/reflection.rb +71 -57
  147. data/lib/active_record/relation.rb +96 -67
  148. data/lib/active_record/relation/batches.rb +38 -31
  149. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  150. data/lib/active_record/relation/calculations.rb +101 -44
  151. data/lib/active_record/relation/delegation.rb +2 -1
  152. data/lib/active_record/relation/finder_methods.rb +45 -15
  153. data/lib/active_record/relation/from_clause.rb +1 -1
  154. data/lib/active_record/relation/merger.rb +27 -25
  155. data/lib/active_record/relation/predicate_builder.rb +59 -38
  156. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  157. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  158. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  159. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  160. data/lib/active_record/relation/query_methods.rb +333 -195
  161. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  162. data/lib/active_record/relation/spawn_methods.rb +8 -7
  163. data/lib/active_record/relation/where_clause.rb +104 -57
  164. data/lib/active_record/result.rb +41 -33
  165. data/lib/active_record/runtime_registry.rb +2 -2
  166. data/lib/active_record/sanitization.rb +6 -17
  167. data/lib/active_record/schema_dumper.rb +34 -4
  168. data/lib/active_record/schema_migration.rb +2 -8
  169. data/lib/active_record/scoping/named.rb +6 -17
  170. data/lib/active_record/secure_token.rb +16 -8
  171. data/lib/active_record/serialization.rb +5 -3
  172. data/lib/active_record/signed_id.rb +116 -0
  173. data/lib/active_record/statement_cache.rb +20 -4
  174. data/lib/active_record/store.rb +2 -2
  175. data/lib/active_record/suppressor.rb +2 -2
  176. data/lib/active_record/table_metadata.rb +42 -51
  177. data/lib/active_record/tasks/database_tasks.rb +140 -113
  178. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  179. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  180. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  181. data/lib/active_record/test_databases.rb +5 -4
  182. data/lib/active_record/test_fixtures.rb +37 -16
  183. data/lib/active_record/timestamp.rb +4 -6
  184. data/lib/active_record/touch_later.rb +21 -21
  185. data/lib/active_record/transactions.rb +19 -66
  186. data/lib/active_record/type.rb +8 -1
  187. data/lib/active_record/type/serialized.rb +6 -2
  188. data/lib/active_record/type/time.rb +10 -0
  189. data/lib/active_record/type_caster/connection.rb +0 -1
  190. data/lib/active_record/type_caster/map.rb +8 -5
  191. data/lib/active_record/validations.rb +1 -0
  192. data/lib/active_record/validations/numericality.rb +35 -0
  193. data/lib/active_record/validations/uniqueness.rb +24 -4
  194. data/lib/arel.rb +5 -13
  195. data/lib/arel/attributes/attribute.rb +4 -0
  196. data/lib/arel/collectors/bind.rb +5 -0
  197. data/lib/arel/collectors/composite.rb +8 -0
  198. data/lib/arel/collectors/sql_string.rb +7 -0
  199. data/lib/arel/collectors/substitute_binds.rb +7 -0
  200. data/lib/arel/nodes.rb +3 -1
  201. data/lib/arel/nodes/binary.rb +82 -8
  202. data/lib/arel/nodes/bind_param.rb +8 -0
  203. data/lib/arel/nodes/casted.rb +21 -9
  204. data/lib/arel/nodes/equality.rb +6 -9
  205. data/lib/arel/nodes/grouping.rb +3 -0
  206. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  207. data/lib/arel/nodes/in.rb +8 -1
  208. data/lib/arel/nodes/infix_operation.rb +13 -1
  209. data/lib/arel/nodes/join_source.rb +1 -1
  210. data/lib/arel/nodes/node.rb +7 -6
  211. data/lib/arel/nodes/ordering.rb +27 -0
  212. data/lib/arel/nodes/sql_literal.rb +3 -0
  213. data/lib/arel/nodes/table_alias.rb +7 -3
  214. data/lib/arel/nodes/unary.rb +0 -1
  215. data/lib/arel/predications.rb +12 -18
  216. data/lib/arel/select_manager.rb +1 -2
  217. data/lib/arel/table.rb +13 -5
  218. data/lib/arel/visitors.rb +0 -7
  219. data/lib/arel/visitors/dot.rb +14 -2
  220. data/lib/arel/visitors/mysql.rb +11 -1
  221. data/lib/arel/visitors/postgresql.rb +15 -4
  222. data/lib/arel/visitors/to_sql.rb +89 -78
  223. data/lib/rails/generators/active_record/migration.rb +6 -1
  224. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  225. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  226. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  227. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  228. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  229. metadata +25 -26
  230. data/lib/active_record/advisory_lock_base.rb +0 -18
  231. data/lib/active_record/attribute_decorators.rb +0 -88
  232. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  233. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  234. data/lib/active_record/define_callbacks.rb +0 -22
  235. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  236. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  237. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  238. data/lib/arel/attributes.rb +0 -22
  239. data/lib/arel/visitors/depth_first.rb +0 -203
  240. data/lib/arel/visitors/ibm_db.rb +0 -34
  241. data/lib/arel/visitors/informix.rb +0 -62
  242. data/lib/arel/visitors/mssql.rb +0 -156
  243. data/lib/arel/visitors/oracle.rb +0 -158
  244. data/lib/arel/visitors/oracle12.rb +0 -65
  245. 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)
@@ -289,8 +271,10 @@ module ActiveRecord
289
271
  if options[:on]
290
272
  fire_on = Array(options[:on])
291
273
  assert_valid_transaction_action(fire_on)
292
- options[:if] = Array(options[:if])
293
- options[:if].unshift(-> { transaction_include_any_action?(fire_on) })
274
+ options[:if] = [
275
+ -> { transaction_include_any_action?(fire_on) },
276
+ *options[:if]
277
+ ]
294
278
  end
295
279
  end
296
280
 
@@ -302,7 +286,7 @@ module ActiveRecord
302
286
  end
303
287
 
304
288
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
305
- def transaction(options = {}, &block)
289
+ def transaction(**options, &block)
306
290
  self.class.transaction(**options, &block)
307
291
  end
308
292
 
@@ -310,11 +294,11 @@ module ActiveRecord
310
294
  with_transaction_returning_status { super }
311
295
  end
312
296
 
313
- def save(*, **) #:nodoc:
297
+ def save(**) #:nodoc:
314
298
  with_transaction_returning_status { super }
315
299
  end
316
300
 
317
- def save!(*, **) #:nodoc:
301
+ def save!(**) #:nodoc:
318
302
  with_transaction_returning_status { super }
319
303
  end
320
304
 
@@ -323,7 +307,6 @@ module ActiveRecord
323
307
  end
324
308
 
325
309
  def before_committed! # :nodoc:
326
- _run_before_commit_without_transaction_enrollment_callbacks
327
310
  _run_before_commit_callbacks
328
311
  end
329
312
 
@@ -335,7 +318,6 @@ module ActiveRecord
335
318
  force_clear_transaction_record_state
336
319
  if should_run_callbacks
337
320
  @_committed_already_called = true
338
- _run_commit_without_transaction_enrollment_callbacks
339
321
  _run_commit_callbacks
340
322
  end
341
323
  ensure
@@ -347,7 +329,6 @@ module ActiveRecord
347
329
  def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
348
330
  if should_run_callbacks
349
331
  _run_rollback_callbacks
350
- _run_rollback_without_transaction_enrollment_callbacks
351
332
  end
352
333
  ensure
353
334
  restore_transaction_record_state(force_restore_state)
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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"
@@ -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,
data/lib/arel.rb CHANGED
@@ -12,7 +12,7 @@ require "arel/math"
12
12
  require "arel/alias_predication"
13
13
  require "arel/order_predications"
14
14
  require "arel/table"
15
- require "arel/attributes"
15
+ require "arel/attributes/attribute"
16
16
 
17
17
  require "arel/visitors"
18
18
  require "arel/collectors/sql_string"
@@ -43,20 +43,12 @@ module Arel
43
43
  end
44
44
 
45
45
  def self.arel_node?(value) # :nodoc:
46
- value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
46
+ value.is_a?(Arel::Nodes::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
47
47
  end
48
48
 
49
- def self.fetch_attribute(value) # :nodoc:
50
- case value
51
- when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
52
- if value.left.is_a?(Arel::Attributes::Attribute)
53
- yield value.left
54
- elsif value.right.is_a?(Arel::Attributes::Attribute)
55
- yield value.right
56
- end
49
+ def self.fetch_attribute(value, &block) # :nodoc:
50
+ unless String === value
51
+ value.fetch_attribute(&block)
57
52
  end
58
53
  end
59
-
60
- ## Convenience Alias
61
- Node = Arel::Nodes::Node # :nodoc:
62
54
  end
@@ -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