activerecord 5.0.0.1 → 5.0.1.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +196 -2
  3. data/README.rdoc +1 -1
  4. data/lib/active_record.rb +1 -1
  5. data/lib/active_record/aggregations.rb +4 -2
  6. data/lib/active_record/association_relation.rb +4 -1
  7. data/lib/active_record/associations.rb +5 -0
  8. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
  9. data/lib/active_record/associations/builder/singular_association.rb +10 -1
  10. data/lib/active_record/associations/collection_association.rb +22 -17
  11. data/lib/active_record/associations/collection_proxy.rb +20 -7
  12. data/lib/active_record/associations/has_many_through_association.rb +4 -0
  13. data/lib/active_record/associations/join_dependency.rb +10 -4
  14. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  15. data/lib/active_record/associations/preloader/association.rb +18 -4
  16. data/lib/active_record/associations/preloader/collection_association.rb +0 -1
  17. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  18. data/lib/active_record/associations/singular_association.rb +8 -2
  19. data/lib/active_record/attribute.rb +3 -3
  20. data/lib/active_record/attribute_methods.rb +3 -7
  21. data/lib/active_record/attribute_methods/primary_key.rb +14 -1
  22. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  23. data/lib/active_record/attribute_set.rb +2 -0
  24. data/lib/active_record/attribute_set/builder.rb +29 -7
  25. data/lib/active_record/attributes.rb +3 -3
  26. data/lib/active_record/autosave_association.rb +15 -11
  27. data/lib/active_record/base.rb +1 -1
  28. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +40 -32
  29. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  30. data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -0
  31. data/lib/active_record/connection_adapters/abstract/quoting.rb +4 -4
  32. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -7
  33. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -33
  34. data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -5
  35. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +42 -45
  36. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  37. data/lib/active_record/connection_adapters/mysql/database_statements.rb +6 -23
  38. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  39. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -5
  40. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
  41. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -1
  42. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  43. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  44. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +7 -1
  45. data/lib/active_record/connection_adapters/postgresql_adapter.rb +6 -2
  46. data/lib/active_record/core.rb +3 -1
  47. data/lib/active_record/enum.rb +6 -5
  48. data/lib/active_record/gem_version.rb +2 -2
  49. data/lib/active_record/integration.rb +13 -10
  50. data/lib/active_record/migration.rb +6 -5
  51. data/lib/active_record/model_schema.rb +134 -47
  52. data/lib/active_record/no_touching.rb +4 -0
  53. data/lib/active_record/persistence.rb +10 -4
  54. data/lib/active_record/query_cache.rb +13 -15
  55. data/lib/active_record/querying.rb +3 -3
  56. data/lib/active_record/railties/controller_runtime.rb +1 -1
  57. data/lib/active_record/reflection.rb +8 -0
  58. data/lib/active_record/relation.rb +7 -4
  59. data/lib/active_record/relation/calculations.rb +11 -11
  60. data/lib/active_record/relation/delegation.rb +1 -1
  61. data/lib/active_record/relation/finder_methods.rb +11 -9
  62. data/lib/active_record/relation/query_methods.rb +3 -3
  63. data/lib/active_record/result.rb +7 -1
  64. data/lib/active_record/sanitization.rb +11 -1
  65. data/lib/active_record/schema_dumper.rb +10 -17
  66. data/lib/active_record/scoping/named.rb +1 -1
  67. data/lib/active_record/statement_cache.rb +2 -2
  68. data/lib/active_record/table_metadata.rb +4 -3
  69. data/lib/active_record/touch_later.rb +6 -1
  70. data/lib/active_record/type/internal/abstract_json.rb +5 -1
  71. data/lib/active_record/validations/uniqueness.rb +3 -4
  72. metadata +9 -10
@@ -203,6 +203,10 @@ module ActiveRecord
203
203
  def invertible_for?(record)
204
204
  false
205
205
  end
206
+
207
+ def append_record(record)
208
+ @target << record
209
+ end
206
210
  end
207
211
  end
208
212
  end
@@ -272,7 +272,11 @@ module ActiveRecord
272
272
  construct(model, node, row, rs, seen, model_cache, aliases)
273
273
  else
274
274
  model = construct_model(ar_parent, node, row, model_cache, id, aliases)
275
- model.readonly!
275
+
276
+ if node.reflection.scope_for(node.base_klass).readonly_value
277
+ model.readonly!
278
+ end
279
+
276
280
  seen[ar_parent.object_id][node.base_klass][id] = model
277
281
  construct(model, node, row, rs, seen, model_cache, aliases)
278
282
  end
@@ -280,17 +284,19 @@ module ActiveRecord
280
284
  end
281
285
 
282
286
  def construct_model(record, node, row, model_cache, id, aliases)
283
- model = model_cache[node][id] ||= node.instantiate(row,
284
- aliases.column_aliases(node))
285
287
  other = record.association(node.reflection.name)
286
288
 
289
+ model = model_cache[node][id] ||=
290
+ node.instantiate(row, aliases.column_aliases(node)) do |m|
291
+ other.set_inverse_instance(m)
292
+ end
293
+
287
294
  if node.reflection.collection?
288
295
  other.target.push(model)
289
296
  else
290
297
  other.target = model
291
298
  end
292
299
 
293
- other.set_inverse_instance(model)
294
300
  model
295
301
  end
296
302
  end
@@ -62,8 +62,8 @@ module ActiveRecord
62
62
  hash
63
63
  end
64
64
 
65
- def instantiate(row, aliases)
66
- base_klass.instantiate(extract_record(row, aliases))
65
+ def instantiate(row, aliases, &block)
66
+ base_klass.instantiate(extract_record(row, aliases), &block)
67
67
  end
68
68
  end
69
69
  end
@@ -62,7 +62,12 @@ module ActiveRecord
62
62
  private
63
63
 
64
64
  def associated_records_by_owner(preloader)
65
- records = load_records
65
+ records = load_records do |record|
66
+ owner = owners_by_key[convert_key(record[association_key_name])]
67
+ association = owner.association(reflection.name)
68
+ association.set_inverse_instance(record)
69
+ end
70
+
66
71
  owners.each_with_object({}) do |owner, result|
67
72
  result[owner] = records[convert_key(owner[owner_key_name])] || []
68
73
  end
@@ -79,6 +84,15 @@ module ActiveRecord
79
84
  @owner_keys
80
85
  end
81
86
 
87
+ def owners_by_key
88
+ unless defined?(@owners_by_key)
89
+ @owners_by_key = owners.each_with_object({}) do |owner, h|
90
+ h[convert_key(owner[owner_key_name])] = owner
91
+ end
92
+ end
93
+ @owners_by_key
94
+ end
95
+
82
96
  def key_conversion_required?
83
97
  @key_conversion_required ||= association_key_type != owner_key_type
84
98
  end
@@ -99,13 +113,13 @@ module ActiveRecord
99
113
  @model.type_for_attribute(owner_key_name.to_s).type
100
114
  end
101
115
 
102
- def load_records
116
+ def load_records(&block)
103
117
  return {} if owner_keys.empty?
104
118
  # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
105
119
  # Make several smaller queries if necessary or make one query if the adapter supports it
106
120
  slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
107
121
  @preloaded_records = slices.flat_map do |slice|
108
- records_for(slice)
122
+ records_for(slice).load(&block)
109
123
  end
110
124
  @preloaded_records.group_by do |record|
111
125
  convert_key(record[association_key_name])
@@ -113,7 +127,7 @@ module ActiveRecord
113
127
  end
114
128
 
115
129
  def reflection_scope
116
- @reflection_scope ||= reflection.scope ? klass.unscoped.instance_exec(nil, &reflection.scope) : klass.unscoped
130
+ @reflection_scope ||= reflection.scope_for(klass)
117
131
  end
118
132
 
119
133
  def build_scope
@@ -9,7 +9,6 @@ module ActiveRecord
9
9
  association = owner.association(reflection.name)
10
10
  association.loaded!
11
11
  association.target.concat(records)
12
- records.each { |record| association.set_inverse_instance(record) }
13
12
  end
14
13
  end
15
14
  end
@@ -11,7 +11,6 @@ module ActiveRecord
11
11
 
12
12
  association = owner.association(reflection.name)
13
13
  association.target = record
14
- association.set_inverse_instance(record) if record
15
14
  end
16
15
  end
17
16
 
@@ -6,8 +6,7 @@ module ActiveRecord
6
6
  if force_reload && klass
7
7
  ActiveSupport::Deprecation.warn(<<-MSG.squish)
8
8
  Passing an argument to force an association to reload is now
9
- deprecated and will be removed in Rails 5.1. Please call `reload`
10
- on the parent object instead.
9
+ deprecated and will be removed in Rails 5.1. Please call `reload_#{reflection.name}` instead.
11
10
  MSG
12
11
 
13
12
  klass.uncached { reload }
@@ -38,6 +37,13 @@ module ActiveRecord
38
37
  record
39
38
  end
40
39
 
40
+ # Implements the reload reader method, e.g. foo.reload_bar for
41
+ # Foo.has_one :bar
42
+ def force_reload_reader
43
+ klass.uncached { reload }
44
+ target
45
+ end
46
+
41
47
  private
42
48
 
43
49
  def create_scope
@@ -65,7 +65,7 @@ module ActiveRecord
65
65
 
66
66
  def with_value_from_user(value)
67
67
  type.assert_valid_value(value)
68
- self.class.from_user(name, value, type, self)
68
+ self.class.from_user(name, value, type, original_attribute || self)
69
69
  end
70
70
 
71
71
  def with_value_from_database(value)
@@ -132,7 +132,7 @@ module ActiveRecord
132
132
  end
133
133
 
134
134
  def _original_value_for_database
135
- value_for_database
135
+ type.serialize(original_value)
136
136
  end
137
137
 
138
138
  class FromDatabase < Attribute # :nodoc:
@@ -160,7 +160,7 @@ module ActiveRecord
160
160
  value
161
161
  end
162
162
 
163
- def changed_in_place_from?(old_value)
163
+ def changed_in_place?
164
164
  false
165
165
  end
166
166
  end
@@ -279,9 +279,8 @@ module ActiveRecord
279
279
  # Returns an <tt>#inspect</tt>-like string for the value of the
280
280
  # attribute +attr_name+. String attributes are truncated up to 50
281
281
  # characters, Date and Time attributes are returned in the
282
- # <tt>:db</tt> format, Array attributes are truncated up to 10 values.
283
- # Other attributes return the value of <tt>#inspect</tt> without
284
- # modification.
282
+ # <tt>:db</tt> format. Other attributes return the value of
283
+ # <tt>#inspect</tt> without modification.
285
284
  #
286
285
  # person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
287
286
  #
@@ -292,7 +291,7 @@ module ActiveRecord
292
291
  # # => "\"2012-10-22 00:15:07\""
293
292
  #
294
293
  # person.attribute_for_inspect(:tag_ids)
295
- # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]"
294
+ # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
296
295
  def attribute_for_inspect(attr_name)
297
296
  value = read_attribute(attr_name)
298
297
 
@@ -300,9 +299,6 @@ module ActiveRecord
300
299
  "#{value[0, 50]}...".inspect
301
300
  elsif value.is_a?(Date) || value.is_a?(Time)
302
301
  %("#{value.to_s(:db)}")
303
- elsif value.is_a?(Array) && value.size > 10
304
- inspected = value.first(10).inspect
305
- %(#{inspected[0...-1]}, ...])
306
302
  else
307
303
  value.inspect
308
304
  end
@@ -95,7 +95,8 @@ module ActiveRecord
95
95
  base_name.foreign_key
96
96
  else
97
97
  if ActiveRecord::Base != self && table_exists?
98
- connection.schema_cache.primary_keys(table_name)
98
+ pk = connection.schema_cache.primary_keys(table_name)
99
+ suppress_composite_primary_key(pk)
99
100
  else
100
101
  'id'
101
102
  end
@@ -122,6 +123,18 @@ module ActiveRecord
122
123
  @quoted_primary_key = nil
123
124
  @attributes_builder = nil
124
125
  end
126
+
127
+ private
128
+
129
+ def suppress_composite_primary_key(pk)
130
+ return pk unless pk.is_a?(Array)
131
+
132
+ warn <<-WARNING.strip_heredoc
133
+ WARNING: Active Record does not support composite primary key.
134
+
135
+ #{table_name} has composite primary key. Composite primary key is ignored.
136
+ WARNING
137
+ end
125
138
  end
126
139
  end
127
140
  end
@@ -39,7 +39,7 @@ module ActiveRecord
39
39
  end
40
40
 
41
41
  def set_time_zone_without_conversion(value)
42
- ::Time.zone.local_to_utc(value).in_time_zone
42
+ ::Time.zone.local_to_utc(value).in_time_zone if value
43
43
  end
44
44
 
45
45
  def map_avoiding_infinite_recursion(value)
@@ -2,6 +2,8 @@ require 'active_record/attribute_set/builder'
2
2
 
3
3
  module ActiveRecord
4
4
  class AttributeSet # :nodoc:
5
+ delegate :fetch, to: :attributes
6
+
5
7
  def initialize(attributes)
6
8
  @attributes = attributes
7
9
  end
@@ -3,11 +3,12 @@ require 'active_record/attribute'
3
3
  module ActiveRecord
4
4
  class AttributeSet # :nodoc:
5
5
  class Builder # :nodoc:
6
- attr_reader :types, :always_initialized
6
+ attr_reader :types, :always_initialized, :default
7
7
 
8
- def initialize(types, always_initialized = nil)
8
+ def initialize(types, always_initialized = nil, &default)
9
9
  @types = types
10
10
  @always_initialized = always_initialized
11
+ @default = default
11
12
  end
12
13
 
13
14
  def build_from_database(values = {}, additional_types = {})
@@ -15,21 +16,22 @@ module ActiveRecord
15
16
  values[always_initialized] = nil
16
17
  end
17
18
 
18
- attributes = LazyAttributeHash.new(types, values, additional_types)
19
+ attributes = LazyAttributeHash.new(types, values, additional_types, &default)
19
20
  AttributeSet.new(attributes)
20
21
  end
21
22
  end
22
23
  end
23
24
 
24
25
  class LazyAttributeHash # :nodoc:
25
- delegate :transform_values, :each_key, to: :materialize
26
+ delegate :transform_values, :each_key, :fetch, to: :materialize
26
27
 
27
- def initialize(types, values, additional_types)
28
+ def initialize(types, values, additional_types, &default)
28
29
  @types = types
29
30
  @values = values
30
31
  @additional_types = additional_types
31
32
  @materialized = false
32
33
  @delegate_hash = {}
34
+ @default = default || proc {}
33
35
  end
34
36
 
35
37
  def key?(key)
@@ -76,9 +78,29 @@ module ActiveRecord
76
78
  end
77
79
  end
78
80
 
81
+ def marshal_dump
82
+ materialize
83
+ end
84
+
85
+ def marshal_load(delegate_hash)
86
+ @delegate_hash = delegate_hash
87
+ @types = {}
88
+ @values = {}
89
+ @additional_types = {}
90
+ @materialized = true
91
+ end
92
+
93
+ def encode_with(coder)
94
+ coder["delegate_hash"] = materialize
95
+ end
96
+
97
+ def init_with(coder)
98
+ marshal_load(coder["delegate_hash"])
99
+ end
100
+
79
101
  protected
80
102
 
81
- attr_reader :types, :values, :additional_types, :delegate_hash
103
+ attr_reader :types, :values, :additional_types, :delegate_hash, :default
82
104
 
83
105
  def materialize
84
106
  unless @materialized
@@ -101,7 +123,7 @@ module ActiveRecord
101
123
  if value_present
102
124
  delegate_hash[name] = Attribute.from_database(name, value, type)
103
125
  elsif types.key?(name)
104
- delegate_hash[name] = Attribute.uninitialized(name, type)
126
+ delegate_hash[name] = default.call(name) || Attribute.uninitialized(name, type)
105
127
  end
106
128
  end
107
129
  end
@@ -34,10 +34,10 @@ module ActiveRecord
34
34
  # is not passed, the previous default value (if any) will be used.
35
35
  # Otherwise, the default will be +nil+.
36
36
  #
37
- # +array+ (PG only) specifies that the type should be an array (see the
37
+ # +array+ (PostgreSQL only) specifies that the type should be an array (see the
38
38
  # examples below).
39
39
  #
40
- # +range+ (PG only) specifies that the type should be a range (see the
40
+ # +range+ (PostgreSQL only) specifies that the type should be a range (see the
41
41
  # examples below).
42
42
  #
43
43
  # ==== Examples
@@ -253,7 +253,7 @@ module ActiveRecord
253
253
  name,
254
254
  value,
255
255
  type,
256
- _default_attributes[name],
256
+ _default_attributes.fetch(name.to_s) { nil },
257
257
  )
258
258
  else
259
259
  default_attribute = Attribute.from_database(name, value, type)
@@ -329,26 +329,20 @@ module ActiveRecord
329
329
  return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
330
330
 
331
331
  validation_context = self.validation_context unless [:create, :update].include?(self.validation_context)
332
+
332
333
  unless valid = record.valid?(validation_context)
333
334
  if reflection.options[:autosave]
334
335
  indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord::Base.index_nested_attribute_errors)
335
336
 
336
337
  record.errors.each do |attribute, message|
337
- if indexed_attribute
338
- attribute = "#{reflection.name}[#{index}].#{attribute}"
339
- else
340
- attribute = "#{reflection.name}.#{attribute}"
341
- end
338
+ attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
342
339
  errors[attribute] << message
343
340
  errors[attribute].uniq!
344
341
  end
345
342
 
346
343
  record.errors.details.each_key do |attribute|
347
- if indexed_attribute
348
- reflection_attribute = "#{reflection.name}[#{index}].#{attribute}"
349
- else
350
- reflection_attribute = "#{reflection.name}.#{attribute}"
351
- end
344
+ reflection_attribute =
345
+ normalize_reflection_attribute(indexed_attribute, reflection, index, attribute).to_sym
352
346
 
353
347
  record.errors.details[attribute].each do |error|
354
348
  errors.details[reflection_attribute] << error
@@ -362,6 +356,14 @@ module ActiveRecord
362
356
  valid
363
357
  end
364
358
 
359
+ def normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
360
+ if indexed_attribute
361
+ "#{reflection.name}[#{index}].#{attribute}"
362
+ else
363
+ "#{reflection.name}.#{attribute}"
364
+ end
365
+ end
366
+
365
367
  # Is used as a before_save callback to check while saving a collection
366
368
  # association whether or not the parent was a new record before saving.
367
369
  def before_save_collection_association
@@ -457,7 +459,9 @@ module ActiveRecord
457
459
  # In addition, it will destroy the association if it was marked for destruction.
458
460
  def save_belongs_to_association(reflection)
459
461
  association = association_instance_get(reflection.name)
460
- record = association && association.load_target
462
+ return unless association && association.loaded? && !association.stale_target?
463
+
464
+ record = association.load_target
461
465
  if record && !record.destroyed?
462
466
  autosave = reflection.options[:autosave]
463
467
 
@@ -312,8 +312,8 @@ module ActiveRecord #:nodoc:
312
312
  include NestedAttributes
313
313
  include Aggregations
314
314
  include Transactions
315
- include NoTouching
316
315
  include TouchLater
316
+ include NoTouching
317
317
  include Reflection
318
318
  include Serialization
319
319
  include Store
@@ -307,6 +307,7 @@ module ActiveRecord
307
307
  end
308
308
 
309
309
  include MonitorMixin
310
+ include QueryCache::ConnectionPoolConfiguration
310
311
 
311
312
  attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
312
313
  attr_reader :spec, :connections, :size, :reaper
@@ -349,8 +350,7 @@ module ActiveRecord
349
350
  # currently in the process of independently establishing connections to the DB.
350
351
  @now_connecting = 0
351
352
 
352
- # A boolean toggle that allows/disallows new connections.
353
- @new_cons_enabled = true
353
+ @threads_blocking_new_connections = 0
354
354
 
355
355
  @available = ConnectionLeasingQueue.new self
356
356
  end
@@ -415,7 +415,10 @@ module ActiveRecord
415
415
  with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
416
416
  synchronize do
417
417
  @connections.each do |conn|
418
- checkin conn
418
+ if conn.in_use?
419
+ conn.steal!
420
+ checkin conn
421
+ end
419
422
  conn.disconnect!
420
423
  end
421
424
  @connections = []
@@ -442,33 +445,19 @@ module ActiveRecord
442
445
  # connections in the pool within a timeout interval (default duration is
443
446
  # <tt>spec.config[:checkout_timeout] * 2</tt> seconds).
444
447
  def clear_reloadable_connections(raise_on_acquisition_timeout = true)
445
- num_new_conns_required = 0
446
-
447
448
  with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
448
449
  synchronize do
449
450
  @connections.each do |conn|
450
- checkin conn
451
+ if conn.in_use?
452
+ conn.steal!
453
+ checkin conn
454
+ end
451
455
  conn.disconnect! if conn.requires_reloading?
452
456
  end
453
457
  @connections.delete_if(&:requires_reloading?)
454
-
455
458
  @available.clear
456
-
457
- if @connections.size < @size
458
- # because of the pruning done by this method, we might be running
459
- # low on connections, while threads stuck in queue are helpless
460
- # (not being able to establish new connections for themselves),
461
- # see also more detailed explanation in +remove+
462
- num_new_conns_required = num_waiting_in_queue - @connections.size
463
- end
464
-
465
- @connections.each do |conn|
466
- @available.add conn
467
- end
468
459
  end
469
460
  end
470
-
471
- bulk_make_new_connections(num_new_conns_required) if num_new_conns_required > 0
472
461
  end
473
462
 
474
463
  # Clears the cache which maps classes and re-connects connections that
@@ -556,17 +545,17 @@ module ActiveRecord
556
545
  stale_connections = synchronize do
557
546
  @connections.select do |conn|
558
547
  conn.in_use? && !conn.owner.alive?
548
+ end.each do |conn|
549
+ conn.steal!
559
550
  end
560
551
  end
561
552
 
562
553
  stale_connections.each do |conn|
563
- synchronize do
564
- if conn.active?
565
- conn.reset!
566
- checkin conn
567
- else
568
- remove conn
569
- end
554
+ if conn.active?
555
+ conn.reset!
556
+ checkin conn
557
+ else
558
+ remove conn
570
559
  end
571
560
  end
572
561
  end
@@ -675,13 +664,32 @@ module ActiveRecord
675
664
  end
676
665
 
677
666
  def with_new_connections_blocked
678
- previous_value = nil
679
667
  synchronize do
680
- previous_value, @new_cons_enabled = @new_cons_enabled, false
668
+ @threads_blocking_new_connections += 1
681
669
  end
670
+
682
671
  yield
683
672
  ensure
684
- synchronize { @new_cons_enabled = previous_value }
673
+ num_new_conns_required = 0
674
+
675
+ synchronize do
676
+ @threads_blocking_new_connections -= 1
677
+
678
+ if @threads_blocking_new_connections.zero?
679
+ @available.clear
680
+
681
+ num_new_conns_required = num_waiting_in_queue
682
+
683
+ @connections.each do |conn|
684
+ next if conn.in_use?
685
+
686
+ @available.add conn
687
+ num_new_conns_required -= 1
688
+ end
689
+ end
690
+ end
691
+
692
+ bulk_make_new_connections(num_new_conns_required) if num_new_conns_required > 0
685
693
  end
686
694
 
687
695
  # Acquire a connection by one of 1) immediately removing one
@@ -733,7 +741,7 @@ module ActiveRecord
733
741
  # and increment @now_connecting, to prevent overstepping this pool's @size
734
742
  # constraint
735
743
  do_checkout = synchronize do
736
- if @new_cons_enabled && (@connections.size + @now_connecting) < @size
744
+ if @threads_blocking_new_connections.zero? && (@connections.size + @now_connecting) < @size
737
745
  @now_connecting += 1
738
746
  end
739
747
  end