activerecord 6.1.0.rc1 → 6.1.2.1

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

Potentially problematic release.


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

Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +177 -20
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/aggregations.rb +4 -4
  5. data/lib/active_record/association_relation.rb +10 -0
  6. data/lib/active_record/associations.rb +6 -2
  7. data/lib/active_record/associations/association.rb +14 -9
  8. data/lib/active_record/associations/association_scope.rb +7 -5
  9. data/lib/active_record/associations/belongs_to_association.rb +7 -3
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  11. data/lib/active_record/associations/builder/association.rb +23 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +2 -2
  13. data/lib/active_record/associations/has_many_association.rb +1 -1
  14. data/lib/active_record/associations/join_dependency.rb +2 -2
  15. data/lib/active_record/associations/join_dependency/join_association.rb +8 -7
  16. data/lib/active_record/attribute_methods.rb +13 -7
  17. data/lib/active_record/attribute_methods/serialization.rb +8 -2
  18. data/lib/active_record/attributes.rb +6 -1
  19. data/lib/active_record/callbacks.rb +121 -1
  20. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +8 -3
  21. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  22. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
  23. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +7 -1
  24. data/lib/active_record/connection_adapters/abstract/transaction.rb +24 -18
  25. data/lib/active_record/connection_adapters/abstract_adapter.rb +23 -8
  26. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +6 -10
  27. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +1 -2
  28. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -1
  29. data/lib/active_record/connection_adapters/pool_config.rb +13 -3
  30. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
  31. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
  32. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  33. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -3
  34. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
  35. data/lib/active_record/connection_handling.rb +11 -3
  36. data/lib/active_record/core.rb +51 -32
  37. data/lib/active_record/database_configurations/url_config.rb +1 -1
  38. data/lib/active_record/enum.rb +58 -31
  39. data/lib/active_record/fixtures.rb +4 -1
  40. data/lib/active_record/gem_version.rb +2 -2
  41. data/lib/active_record/insert_all.rb +2 -0
  42. data/lib/active_record/internal_metadata.rb +2 -4
  43. data/lib/active_record/locking/optimistic.rb +14 -4
  44. data/lib/active_record/log_subscriber.rb +3 -2
  45. data/lib/active_record/migration/compatibility.rb +2 -1
  46. data/lib/active_record/model_schema.rb +29 -0
  47. data/lib/active_record/railtie.rb +2 -2
  48. data/lib/active_record/railties/console_sandbox.rb +2 -4
  49. data/lib/active_record/railties/databases.rake +29 -7
  50. data/lib/active_record/reflection.rb +2 -1
  51. data/lib/active_record/relation/predicate_builder.rb +6 -9
  52. data/lib/active_record/relation/predicate_builder/association_query_value.rb +3 -4
  53. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +9 -5
  54. data/lib/active_record/relation/query_methods.rb +9 -6
  55. data/lib/active_record/relation/spawn_methods.rb +2 -2
  56. data/lib/active_record/schema_migration.rb +2 -4
  57. data/lib/active_record/signed_id.rb +1 -1
  58. data/lib/active_record/table_metadata.rb +10 -3
  59. data/lib/active_record/tasks/database_tasks.rb +1 -0
  60. data/lib/active_record/transactions.rb +4 -2
  61. metadata +12 -12
@@ -7,8 +7,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
7
7
  end
8
8
 
9
9
  def self.valid_options(options)
10
- valid = super + [:counter_cache, :optional, :default]
11
- valid += [:polymorphic, :foreign_type] if options[:polymorphic]
10
+ valid = super + [:polymorphic, :counter_cache, :optional, :default]
11
+ valid += [:foreign_type] if options[:polymorphic]
12
12
  valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
13
13
  valid
14
14
  end
@@ -42,7 +42,7 @@ module ActiveRecord
42
42
  enqueue_destroy_association(
43
43
  owner_model_name: owner.class.to_s,
44
44
  owner_id: owner.id,
45
- association_class: association_class.to_s,
45
+ association_class: reflection.klass.to_s,
46
46
  association_ids: ids,
47
47
  association_primary_key_column: primary_key_column,
48
48
  ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
@@ -84,7 +84,7 @@ module ActiveRecord
84
84
  @references = {}
85
85
 
86
86
  references.each do |table_name|
87
- @references[table_name.to_sym] = table_name if table_name.is_a?(String)
87
+ @references[table_name.to_sym] = table_name if table_name.is_a?(Arel::Nodes::SqlLiteral)
88
88
  end unless references.empty?
89
89
 
90
90
  joins = make_join_constraints(join_root, join_type)
@@ -195,7 +195,7 @@ module ActiveRecord
195
195
  next table, true
196
196
  end
197
197
 
198
- table_name = @references[reflection.name.to_sym]
198
+ table_name = @references[reflection.name.to_sym]&.to_s
199
199
 
200
200
  table = alias_tracker.aliased_table_for(reflection.klass.arel_table, table_name) do
201
201
  name = reflection.alias_candidate(parent.table_name)
@@ -42,16 +42,17 @@ module ActiveRecord
42
42
  chain.reverse_each do |reflection, table|
43
43
  klass = reflection.klass
44
44
 
45
- join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
45
+ scope = reflection.join_scope(table, foreign_table, foreign_klass)
46
46
 
47
- unless join_scope.references_values.empty?
48
- join_dependency = join_scope.construct_join_dependency(
49
- join_scope.eager_load_values | join_scope.includes_values, Arel::Nodes::OuterJoin
50
- )
51
- join_scope.joins!(join_dependency)
47
+ unless scope.references_values.empty?
48
+ associations = scope.eager_load_values | scope.includes_values
49
+
50
+ unless associations.empty?
51
+ scope.joins! scope.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
52
+ end
52
53
  end
53
54
 
54
- arel = join_scope.arel(alias_tracker.aliases)
55
+ arel = scope.arel(alias_tracker.aliases)
55
56
  nodes = arel.constraints.first
56
57
 
57
58
  if nodes.is_a?(Arel::Nodes::And)
@@ -285,7 +285,7 @@ module ActiveRecord
285
285
  attr_name = attr_name.to_s
286
286
  attr_name = self.class.attribute_aliases[attr_name] || attr_name
287
287
  value = _read_attribute(attr_name)
288
- format_for_inspect(value)
288
+ format_for_inspect(attr_name, value)
289
289
  end
290
290
 
291
291
  # Returns +true+ if the specified +attribute+ has been set by the user or by a
@@ -407,13 +407,19 @@ module ActiveRecord
407
407
  end
408
408
  end
409
409
 
410
- def format_for_inspect(value)
411
- if value.is_a?(String) && value.length > 50
412
- "#{value[0, 50]}...".inspect
413
- elsif value.is_a?(Date) || value.is_a?(Time)
414
- %("#{value.to_s(:inspect)}")
415
- else
410
+ def format_for_inspect(name, value)
411
+ if value.nil?
416
412
  value.inspect
413
+ else
414
+ inspected_value = if value.is_a?(String) && value.length > 50
415
+ "#{value[0, 50]}...".inspect
416
+ elsif value.is_a?(Date) || value.is_a?(Time)
417
+ %("#{value.to_s(:inspect)}")
418
+ else
419
+ value.inspect
420
+ end
421
+
422
+ inspection_filter.filter_param(name, inspected_value)
417
423
  end
418
424
  end
419
425
 
@@ -41,6 +41,12 @@ module ActiveRecord
41
41
  # * +class_name_or_coder+ - Optional, a coder object, which responds to +.load+ and +.dump+
42
42
  # or a class name that the object type should be equal to.
43
43
  #
44
+ # ==== Options
45
+ #
46
+ # +default+ The default value to use when no value is provided. If this option
47
+ # is not passed, the previous default value (if any) will be used.
48
+ # Otherwise, the default will be +nil+.
49
+ #
44
50
  # ==== Example
45
51
  #
46
52
  # # Serialize a preferences attribute.
@@ -57,7 +63,7 @@ module ActiveRecord
57
63
  # class User < ActiveRecord::Base
58
64
  # serialize :preferences, Hash
59
65
  # end
60
- def serialize(attr_name, class_name_or_coder = Object)
66
+ def serialize(attr_name, class_name_or_coder = Object, **options)
61
67
  # When ::JSON is used, force it to go through the Active Support JSON encoder
62
68
  # to ensure special objects (e.g. Active Record models) are dumped correctly
63
69
  # using the #as_json hook.
@@ -69,7 +75,7 @@ module ActiveRecord
69
75
  Coders::YAMLColumn.new(attr_name, class_name_or_coder)
70
76
  end
71
77
 
72
- decorate_attribute_type(attr_name.to_s) do |cast_type|
78
+ decorate_attribute_type(attr_name.to_s, **options) do |cast_type|
73
79
  if type_incompatible_with_serialize?(cast_type, class_name_or_coder)
74
80
  raise ColumnNotSerializableError.new(attr_name, cast_type)
75
81
  end
@@ -12,6 +12,9 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  module ClassMethods
15
+ ##
16
+ # :call-seq: attribute(name, cast_type = nil, **options)
17
+ #
15
18
  # Defines an attribute with a type on this model. It will override the
16
19
  # type of existing attributes if needed. This allows control over how
17
20
  # values are converted to and from SQL when assigned to a model. It also
@@ -170,7 +173,7 @@ module ActiveRecord
170
173
  # class Money < Struct.new(:amount, :currency)
171
174
  # end
172
175
  #
173
- # class MoneyType < Type::Value
176
+ # class MoneyType < ActiveRecord::Type::Value
174
177
  # def initialize(currency_converter:)
175
178
  # @currency_converter = currency_converter
176
179
  # end
@@ -273,6 +276,8 @@ module ActiveRecord
273
276
  def decorate_attribute_type(attr_name, **default)
274
277
  type, options = attributes_to_define_after_schema_loads[attr_name]
275
278
 
279
+ default.with_defaults!(default: options[:default]) if options&.key?(:default)
280
+
276
281
  attribute(attr_name, **default) do |cast_type|
277
282
  if type && !type.is_a?(Proc)
278
283
  cast_type = _lookup_cast_type(attr_name, type, options)
@@ -301,8 +301,128 @@ module ActiveRecord
301
301
  :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
302
302
  ]
303
303
 
304
- module ClassMethods # :nodoc:
304
+ module ClassMethods
305
305
  include ActiveModel::Callbacks
306
+
307
+ ##
308
+ # :method: after_initialize
309
+ #
310
+ # :call-seq: after_initialize(*args, &block)
311
+ #
312
+ # Registers a callback to be called after a record is instantiated. See
313
+ # ActiveRecord::Callbacks for more information.
314
+
315
+ ##
316
+ # :method: after_find
317
+ #
318
+ # :call-seq: after_find(*args, &block)
319
+ #
320
+ # Registers a callback to be called after a record is instantiated
321
+ # via a finder. See ActiveRecord::Callbacks for more information.
322
+
323
+ ##
324
+ # :method: after_touch
325
+ #
326
+ # :call-seq: after_touch(*args, &block)
327
+ #
328
+ # Registers a callback to be called after a record is touched. See
329
+ # ActiveRecord::Callbacks for more information.
330
+
331
+ ##
332
+ # :method: before_save
333
+ #
334
+ # :call-seq: before_save(*args, &block)
335
+ #
336
+ # Registers a callback to be called before a record is saved. See
337
+ # ActiveRecord::Callbacks for more information.
338
+
339
+ ##
340
+ # :method: around_save
341
+ #
342
+ # :call-seq: around_save(*args, &block)
343
+ #
344
+ # Registers a callback to be called around the save of a record. See
345
+ # ActiveRecord::Callbacks for more information.
346
+
347
+ ##
348
+ # :method: after_save
349
+ #
350
+ # :call-seq: after_save(*args, &block)
351
+ #
352
+ # Registers a callback to be called after a record is saved. See
353
+ # ActiveRecord::Callbacks for more information.
354
+
355
+ ##
356
+ # :method: before_create
357
+ #
358
+ # :call-seq: before_create(*args, &block)
359
+ #
360
+ # Registers a callback to be called before a record is created. See
361
+ # ActiveRecord::Callbacks for more information.
362
+
363
+ ##
364
+ # :method: around_create
365
+ #
366
+ # :call-seq: around_create(*args, &block)
367
+ #
368
+ # Registers a callback to be called around the creation of a record. See
369
+ # ActiveRecord::Callbacks for more information.
370
+
371
+ ##
372
+ # :method: after_create
373
+ #
374
+ # :call-seq: after_create(*args, &block)
375
+ #
376
+ # Registers a callback to be called after a record is created. See
377
+ # ActiveRecord::Callbacks for more information.
378
+
379
+ ##
380
+ # :method: before_update
381
+ #
382
+ # :call-seq: before_update(*args, &block)
383
+ #
384
+ # Registers a callback to be called before a record is updated. See
385
+ # ActiveRecord::Callbacks for more information.
386
+
387
+ ##
388
+ # :method: around_update
389
+ #
390
+ # :call-seq: around_update(*args, &block)
391
+ #
392
+ # Registers a callback to be called around the update of a record. See
393
+ # ActiveRecord::Callbacks for more information.
394
+
395
+ ##
396
+ # :method: after_update
397
+ #
398
+ # :call-seq: after_update(*args, &block)
399
+ #
400
+ # Registers a callback to be called after a record is updated. See
401
+ # ActiveRecord::Callbacks for more information.
402
+
403
+ ##
404
+ # :method: before_destroy
405
+ #
406
+ # :call-seq: before_destroy(*args, &block)
407
+ #
408
+ # Registers a callback to be called before a record is destroyed. See
409
+ # ActiveRecord::Callbacks for more information.
410
+
411
+ ##
412
+ # :method: around_destroy
413
+ #
414
+ # :call-seq: around_destroy(*args, &block)
415
+ #
416
+ # Registers a callback to be called around the destruction of a record.
417
+ # See ActiveRecord::Callbacks for more information.
418
+
419
+ ##
420
+ # :method: after_destroy
421
+ #
422
+ # :call-seq: after_destroy(*args, &block)
423
+ #
424
+ # Registers a callback to be called after a record is destroyed. See
425
+ # ActiveRecord::Callbacks for more information.
306
426
  end
307
427
 
308
428
  included do
@@ -23,6 +23,10 @@ module ActiveRecord
23
23
  include ConnectionAdapters::AbstractPool
24
24
 
25
25
  attr_accessor :schema_cache
26
+
27
+ def connection_klass
28
+ nil
29
+ end
26
30
  end
27
31
 
28
32
  # Connection pool base class for managing Active Record database
@@ -356,7 +360,7 @@ module ActiveRecord
356
360
  include ConnectionAdapters::AbstractPool
357
361
 
358
362
  attr_accessor :automatic_reconnect, :checkout_timeout
359
- attr_reader :db_config, :size, :reaper, :pool_config
363
+ attr_reader :db_config, :size, :reaper, :pool_config, :connection_klass
360
364
 
361
365
  delegate :schema_cache, :schema_cache=, to: :pool_config
362
366
 
@@ -371,6 +375,7 @@ module ActiveRecord
371
375
 
372
376
  @pool_config = pool_config
373
377
  @db_config = pool_config.db_config
378
+ @connection_klass = pool_config.connection_klass
374
379
 
375
380
  @checkout_timeout = db_config.checkout_timeout
376
381
  @idle_timeout = db_config.idle_timeout
@@ -381,7 +386,7 @@ module ActiveRecord
381
386
  # registry of which thread owns which connection. Connection ownership is tracked by
382
387
  # the +connection.owner+ attr on each +connection+ instance.
383
388
  # The invariant works like this: if there is mapping of <tt>thread => conn</tt>,
384
- # then that +thread+ does indeed own that +conn+. However, an absence of a such
389
+ # then that +thread+ does indeed own that +conn+. However, an absence of such
385
390
  # mapping does not mean that the +thread+ doesn't own the said connection. In
386
391
  # that case +conn.owner+ attr should be consulted.
387
392
  # Access and modification of <tt>@thread_cached_conns</tt> does not require
@@ -1035,7 +1040,7 @@ module ActiveRecord
1035
1040
  end
1036
1041
  alias :connection_pools :connection_pool_list
1037
1042
 
1038
- def establish_connection(config, owner_name: Base.name, role: ActiveRecord::Base.current_role, shard: Base.current_shard)
1043
+ def establish_connection(config, owner_name: Base, role: ActiveRecord::Base.current_role, shard: Base.current_shard)
1039
1044
  owner_name = config.to_s if config.is_a?(Symbol)
1040
1045
 
1041
1046
  pool_config = resolve_pool_config(config, owner_name)
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  module QueryCache
8
8
  class << self
9
9
  def included(base) #:nodoc:
10
- dirties_query_cache base, :insert, :update, :delete, :truncate, :truncate_tables,
10
+ dirties_query_cache base, :create, :insert, :update, :delete, :truncate, :truncate_tables,
11
11
  :rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
12
12
 
13
13
  base.set_callback :checkout, :after, :configure_query_cache!
@@ -71,6 +71,10 @@ module ActiveRecord
71
71
  end
72
72
  CODE
73
73
  end
74
+
75
+ def aliased_types(name, fallback)
76
+ "timestamp" == name ? :datetime : fallback
77
+ end
74
78
  end
75
79
 
76
80
  AddColumnDefinition = Struct.new(:column) # :nodoc:
@@ -1387,8 +1387,14 @@ module ActiveRecord
1387
1387
 
1388
1388
  checks = []
1389
1389
 
1390
+ if !options.key?(:name) && column_name.is_a?(String) && /\W/.match?(column_name)
1391
+ options[:name] = index_name(table_name, column_name)
1392
+ column_names = []
1393
+ else
1394
+ column_names = index_column_names(column_name || options[:column])
1395
+ end
1396
+
1390
1397
  checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
1391
- column_names = index_column_names(column_name || options[:column])
1392
1398
 
1393
1399
  if column_names.present?
1394
1400
  checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
@@ -317,25 +317,31 @@ module ActiveRecord
317
317
  end
318
318
  raise
319
319
  ensure
320
- if !error && transaction
321
- if Thread.current.status == "aborting"
322
- rollback_transaction
320
+ if transaction
321
+ if error
322
+ # @connection still holds an open transaction, so we must not
323
+ # put it back in the pool for reuse
324
+ @connection.throw_away! unless transaction.state.rolledback?
323
325
  else
324
- if !completed && transaction.written
325
- ActiveSupport::Deprecation.warn(<<~EOW)
326
- Using `return`, `break` or `throw` to exit a transaction block is
327
- deprecated without replacement. If the `throw` came from
328
- `Timeout.timeout(duration)`, pass an exception class as a second
329
- argument so it doesn't use `throw` to abort its block. This results
330
- in the transaction being committed, but in the next release of Rails
331
- it will rollback.
332
- EOW
333
- end
334
- begin
335
- commit_transaction
336
- rescue Exception
337
- rollback_transaction(transaction) unless transaction.state.completed?
338
- raise
326
+ if Thread.current.status == "aborting"
327
+ rollback_transaction
328
+ else
329
+ if !completed && transaction.written
330
+ ActiveSupport::Deprecation.warn(<<~EOW)
331
+ Using `return`, `break` or `throw` to exit a transaction block is
332
+ deprecated without replacement. If the `throw` came from
333
+ `Timeout.timeout(duration)`, pass an exception class as a second
334
+ argument so it doesn't use `throw` to abort its block. This results
335
+ in the transaction being committed, but in the next release of Rails
336
+ it will rollback.
337
+ EOW
338
+ end
339
+ begin
340
+ commit_transaction
341
+ rescue Exception
342
+ rollback_transaction(transaction) unless transaction.state.completed?
343
+ raise
344
+ end
339
345
  end
340
346
  end
341
347
  end
@@ -111,16 +111,21 @@ module ActiveRecord
111
111
  @config.fetch(:use_metadata_table, true)
112
112
  end
113
113
 
114
- # Determines whether writes are currently being prevents.
114
+ # Determines whether writes are currently being prevented.
115
115
  #
116
- # Returns true if the connection is a replica, or if +prevent_writes+
117
- # is set to true.
116
+ # Returns true if the connection is a replica.
117
+ #
118
+ # If the application is using legacy handling, returns
119
+ # true if `connection_handler.prevent_writes` is set.
120
+ #
121
+ # If the application is using the new connection handling
122
+ # will return true based on `current_preventing_writes`.
118
123
  def preventing_writes?
119
- if ActiveRecord::Base.legacy_connection_handling
120
- replica? || ActiveRecord::Base.connection_handler.prevent_writes
121
- else
122
- replica? || ActiveRecord::Base.current_preventing_writes
123
- end
124
+ return true if replica?
125
+ return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord::Base.legacy_connection_handling
126
+ return false if connection_klass.nil?
127
+
128
+ connection_klass.current_preventing_writes
124
129
  end
125
130
 
126
131
  def migrations_paths # :nodoc:
@@ -196,6 +201,10 @@ module ActiveRecord
196
201
  @owner = Thread.current
197
202
  end
198
203
 
204
+ def connection_klass # :nodoc:
205
+ @pool.connection_klass
206
+ end
207
+
199
208
  def schema_cache
200
209
  @pool.get_schema_cache(self)
201
210
  end
@@ -501,6 +510,12 @@ module ActiveRecord
501
510
  # this should be overridden by concrete adapters
502
511
  end
503
512
 
513
+ # Removes the connection from the pool and disconnect it.
514
+ def throw_away!
515
+ pool.remove self
516
+ disconnect!
517
+ end
518
+
504
519
  # Clear any caching the database adapter may be doing.
505
520
  def clear_cache!
506
521
  @lock.synchronize { @statements.clear } if @statements