activerecord 5.0.0 → 5.0.7.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +431 -2
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +4 -1
- data/lib/active_record/associations/association.rb +11 -1
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
- data/lib/active_record/associations/builder/singular_association.rb +10 -1
- data/lib/active_record/associations/collection_association.rb +56 -48
- data/lib/active_record/associations/collection_proxy.rb +38 -20
- data/lib/active_record/associations/has_many_association.rb +1 -7
- data/lib/active_record/associations/has_many_through_association.rb +2 -4
- data/lib/active_record/associations/join_dependency/join_association.rb +6 -11
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +10 -4
- data/lib/active_record/associations/preloader/association.rb +24 -37
- data/lib/active_record/associations/preloader/collection_association.rb +0 -1
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +10 -4
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +38 -17
- data/lib/active_record/attribute.rb +3 -3
- data/lib/active_record/attribute_methods/primary_key.rb +14 -1
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -2
- data/lib/active_record/attribute_methods.rb +3 -7
- data/lib/active_record/attribute_set/builder.rb +37 -13
- data/lib/active_record/attribute_set.rb +2 -0
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +15 -11
- data/lib/active_record/base.rb +1 -1
- data/lib/active_record/collection_cache_key.rb +16 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +41 -33
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +11 -14
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +68 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -12
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -60
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -25
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -6
- data/lib/active_record/connection_adapters/postgresql/column.rb +28 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +32 -3
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +18 -8
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +4 -4
- data/lib/active_record/core.rb +6 -4
- data/lib/active_record/enum.rb +8 -5
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/fixtures.rb +5 -5
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/integration.rb +13 -10
- data/lib/active_record/log_subscriber.rb +19 -17
- data/lib/active_record/migration.rb +35 -14
- data/lib/active_record/model_schema.rb +161 -52
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/persistence.rb +41 -20
- data/lib/active_record/query_cache.rb +15 -17
- data/lib/active_record/querying.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +9 -21
- data/lib/active_record/reflection.rb +20 -0
- data/lib/active_record/relation/batches.rb +10 -10
- data/lib/active_record/relation/calculations.rb +16 -12
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +13 -11
- data/lib/active_record/relation/query_methods.rb +3 -3
- data/lib/active_record/relation.rb +12 -5
- data/lib/active_record/result.rb +7 -1
- data/lib/active_record/sanitization.rb +11 -1
- data/lib/active_record/schema_dumper.rb +10 -17
- data/lib/active_record/scoping/default.rb +5 -1
- data/lib/active_record/scoping/named.rb +18 -6
- data/lib/active_record/scoping.rb +4 -3
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/table_metadata.rb +4 -3
- data/lib/active_record/tasks/database_tasks.rb +14 -11
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/touch_later.rb +6 -1
- data/lib/active_record/transactions.rb +1 -1
- data/lib/active_record/type/internal/abstract_json.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +3 -4
- data/lib/active_record.rb +3 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration.rb +8 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- metadata +7 -8
@@ -197,13 +197,6 @@ module ActiveRecord
|
|
197
197
|
autoload :CollectionAssociation
|
198
198
|
autoload :ForeignAssociation
|
199
199
|
autoload :CollectionProxy
|
200
|
-
|
201
|
-
autoload :BelongsToAssociation
|
202
|
-
autoload :BelongsToPolymorphicAssociation
|
203
|
-
autoload :HasManyAssociation
|
204
|
-
autoload :HasManyThroughAssociation
|
205
|
-
autoload :HasOneAssociation
|
206
|
-
autoload :HasOneThroughAssociation
|
207
200
|
autoload :ThroughAssociation
|
208
201
|
|
209
202
|
module Builder #:nodoc:
|
@@ -218,12 +211,24 @@ module ActiveRecord
|
|
218
211
|
end
|
219
212
|
|
220
213
|
eager_autoload do
|
214
|
+
autoload :BelongsToAssociation
|
215
|
+
autoload :BelongsToPolymorphicAssociation
|
216
|
+
autoload :HasManyAssociation
|
217
|
+
autoload :HasManyThroughAssociation
|
218
|
+
autoload :HasOneAssociation
|
219
|
+
autoload :HasOneThroughAssociation
|
220
|
+
|
221
221
|
autoload :Preloader
|
222
222
|
autoload :JoinDependency
|
223
223
|
autoload :AssociationScope
|
224
224
|
autoload :AliasTracker
|
225
225
|
end
|
226
226
|
|
227
|
+
def self.eager_load!
|
228
|
+
super
|
229
|
+
Preloader.eager_load!
|
230
|
+
end
|
231
|
+
|
227
232
|
# Returns the association instance for the given name, instantiating it if it doesn't already exist
|
228
233
|
def association(name) #:nodoc:
|
229
234
|
association = association_instance_get(name)
|
@@ -312,17 +317,18 @@ module ActiveRecord
|
|
312
317
|
# | | belongs_to |
|
313
318
|
# generated methods | belongs_to | :polymorphic | has_one
|
314
319
|
# ----------------------------------+------------+--------------+---------
|
315
|
-
# other
|
320
|
+
# other | X | X | X
|
316
321
|
# other=(other) | X | X | X
|
317
322
|
# build_other(attributes={}) | X | | X
|
318
323
|
# create_other(attributes={}) | X | | X
|
319
324
|
# create_other!(attributes={}) | X | | X
|
325
|
+
# reload_other | X | X | X
|
320
326
|
#
|
321
327
|
# === Collection associations (one-to-many / many-to-many)
|
322
328
|
# | | | has_many
|
323
329
|
# generated methods | habtm | has_many | :through
|
324
330
|
# ----------------------------------+-------+----------+----------
|
325
|
-
# others
|
331
|
+
# others | X | X | X
|
326
332
|
# others=(other,other,...) | X | X | X
|
327
333
|
# other_ids | X | X | X
|
328
334
|
# other_ids=(id,id,...) | X | X | X
|
@@ -346,6 +352,7 @@ module ActiveRecord
|
|
346
352
|
# others.exists? | X | X | X
|
347
353
|
# others.distinct | X | X | X
|
348
354
|
# others.reset | X | X | X
|
355
|
+
# others.reload | X | X | X
|
349
356
|
#
|
350
357
|
# === Overriding generated methods
|
351
358
|
#
|
@@ -1157,9 +1164,9 @@ module ActiveRecord
|
|
1157
1164
|
# +collection+ is a placeholder for the symbol passed as the +name+ argument, so
|
1158
1165
|
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
|
1159
1166
|
#
|
1160
|
-
# [collection
|
1161
|
-
# Returns
|
1162
|
-
# An empty
|
1167
|
+
# [collection]
|
1168
|
+
# Returns a Relation of all the associated objects.
|
1169
|
+
# An empty Relation is returned if none are found.
|
1163
1170
|
# [collection<<(object, ...)]
|
1164
1171
|
# Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
|
1165
1172
|
# Note that this operation instantly fires update SQL without waiting for the save or update call on the
|
@@ -1216,6 +1223,9 @@ module ActiveRecord
|
|
1216
1223
|
# [collection.create!(attributes = {})]
|
1217
1224
|
# Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid
|
1218
1225
|
# if the record is invalid.
|
1226
|
+
# [collection.reload]
|
1227
|
+
# Returns a Relation of all of the associated objects, forcing a database read.
|
1228
|
+
# An empty Relation is returned if none are found.
|
1219
1229
|
#
|
1220
1230
|
# === Example
|
1221
1231
|
#
|
@@ -1235,6 +1245,7 @@ module ActiveRecord
|
|
1235
1245
|
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
|
1236
1246
|
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
|
1237
1247
|
# * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
|
1248
|
+
# * <tt>Firm#clients.reload</tt>
|
1238
1249
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1239
1250
|
#
|
1240
1251
|
# === Scopes
|
@@ -1371,7 +1382,7 @@ module ActiveRecord
|
|
1371
1382
|
# +association+ is a placeholder for the symbol passed as the +name+ argument, so
|
1372
1383
|
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
|
1373
1384
|
#
|
1374
|
-
# [association
|
1385
|
+
# [association]
|
1375
1386
|
# Returns the associated object. +nil+ is returned if none is found.
|
1376
1387
|
# [association=(associate)]
|
1377
1388
|
# Assigns the associate object, extracts the primary key, sets it as the foreign key,
|
@@ -1388,6 +1399,8 @@ module ActiveRecord
|
|
1388
1399
|
# [create_association!(attributes = {})]
|
1389
1400
|
# Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
|
1390
1401
|
# if the record is invalid.
|
1402
|
+
# [reload_association]
|
1403
|
+
# Returns the associated object, forcing a database read.
|
1391
1404
|
#
|
1392
1405
|
# === Example
|
1393
1406
|
#
|
@@ -1397,6 +1410,7 @@ module ActiveRecord
|
|
1397
1410
|
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
|
1398
1411
|
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
|
1399
1412
|
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
|
1413
|
+
# * <tt>Account#reload_beneficiary</tt>
|
1400
1414
|
#
|
1401
1415
|
# === Scopes
|
1402
1416
|
#
|
@@ -1503,7 +1517,7 @@ module ActiveRecord
|
|
1503
1517
|
# +association+ is a placeholder for the symbol passed as the +name+ argument, so
|
1504
1518
|
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
|
1505
1519
|
#
|
1506
|
-
# [association
|
1520
|
+
# [association]
|
1507
1521
|
# Returns the associated object. +nil+ is returned if none is found.
|
1508
1522
|
# [association=(associate)]
|
1509
1523
|
# Assigns the associate object, extracts the primary key, and sets it as the foreign key.
|
@@ -1517,6 +1531,8 @@ module ActiveRecord
|
|
1517
1531
|
# [create_association!(attributes = {})]
|
1518
1532
|
# Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
|
1519
1533
|
# if the record is invalid.
|
1534
|
+
# [reload_association]
|
1535
|
+
# Returns the associated object, forcing a database read.
|
1520
1536
|
#
|
1521
1537
|
# === Example
|
1522
1538
|
#
|
@@ -1526,6 +1542,7 @@ module ActiveRecord
|
|
1526
1542
|
# * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
|
1527
1543
|
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
|
1528
1544
|
# * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
|
1545
|
+
# * <tt>Post#reload_author</tt>
|
1529
1546
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1530
1547
|
#
|
1531
1548
|
# === Scopes
|
@@ -1661,9 +1678,9 @@ module ActiveRecord
|
|
1661
1678
|
# +collection+ is a placeholder for the symbol passed as the +name+ argument, so
|
1662
1679
|
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
|
1663
1680
|
#
|
1664
|
-
# [collection
|
1665
|
-
# Returns
|
1666
|
-
# An empty
|
1681
|
+
# [collection]
|
1682
|
+
# Returns a Relation of all the associated objects.
|
1683
|
+
# An empty Relation is returned if none are found.
|
1667
1684
|
# [collection<<(object, ...)]
|
1668
1685
|
# Adds one or more objects to the collection by creating associations in the join table
|
1669
1686
|
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
|
@@ -1701,6 +1718,9 @@ module ActiveRecord
|
|
1701
1718
|
# Returns a new object of the collection type that has been instantiated
|
1702
1719
|
# with +attributes+, linked to this object through the join table, and that has already been
|
1703
1720
|
# saved (if it passed the validation).
|
1721
|
+
# [collection.reload]
|
1722
|
+
# Returns a Relation of all of the associated objects, forcing a database read.
|
1723
|
+
# An empty Relation is returned if none are found.
|
1704
1724
|
#
|
1705
1725
|
# === Example
|
1706
1726
|
#
|
@@ -1719,6 +1739,7 @@ module ActiveRecord
|
|
1719
1739
|
# * <tt>Developer#projects.exists?(...)</tt>
|
1720
1740
|
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
|
1721
1741
|
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
|
1742
|
+
# * <tt>Developer#projects.reload</tt>
|
1722
1743
|
# The declaration may include an +options+ hash to specialize the behavior of the association.
|
1723
1744
|
#
|
1724
1745
|
# === Scopes
|
@@ -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
|
-
|
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
|
163
|
+
def changed_in_place?
|
164
164
|
false
|
165
165
|
end
|
166
166
|
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
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
# to a date object, like Date.new(2004, 12, 12)).
|
50
50
|
def read_attribute(attr_name, &block)
|
51
51
|
name = attr_name.to_s
|
52
|
-
name = self.class.primary_key if name ==
|
52
|
+
name = self.class.primary_key if name == "id".freeze && self.class.primary_key
|
53
53
|
_read_attribute(name, &block)
|
54
54
|
end
|
55
55
|
|
@@ -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)
|
@@ -102,7 +102,7 @@ module ActiveRecord
|
|
102
102
|
|
103
103
|
config.active_record.time_zone_aware_types = [:datetime]
|
104
104
|
|
105
|
-
To
|
105
|
+
To use the new behavior, add the following:
|
106
106
|
|
107
107
|
config.active_record.time_zone_aware_types = [:datetime, :time]
|
108
108
|
MESSAGE
|
@@ -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
|
283
|
-
#
|
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
|
@@ -3,33 +3,30 @@ require 'active_record/attribute'
|
|
3
3
|
module ActiveRecord
|
4
4
|
class AttributeSet # :nodoc:
|
5
5
|
class Builder # :nodoc:
|
6
|
-
attr_reader :types, :
|
6
|
+
attr_reader :types, :default_attributes
|
7
7
|
|
8
|
-
def initialize(types,
|
8
|
+
def initialize(types, default_attributes = {})
|
9
9
|
@types = types
|
10
|
-
@
|
10
|
+
@default_attributes = default_attributes
|
11
11
|
end
|
12
12
|
|
13
13
|
def build_from_database(values = {}, additional_types = {})
|
14
|
-
|
15
|
-
values[always_initialized] = nil
|
16
|
-
end
|
17
|
-
|
18
|
-
attributes = LazyAttributeHash.new(types, values, additional_types)
|
14
|
+
attributes = LazyAttributeHash.new(types, values, additional_types, default_attributes)
|
19
15
|
AttributeSet.new(attributes)
|
20
16
|
end
|
21
17
|
end
|
22
18
|
end
|
23
19
|
|
24
20
|
class LazyAttributeHash # :nodoc:
|
25
|
-
delegate :transform_values, :each_key, to: :materialize
|
21
|
+
delegate :transform_values, :each_key, :fetch, :except, to: :materialize
|
26
22
|
|
27
|
-
def initialize(types, values, additional_types)
|
23
|
+
def initialize(types, values, additional_types, default_attributes, delegate_hash = {})
|
28
24
|
@types = types
|
29
25
|
@values = values
|
30
26
|
@additional_types = additional_types
|
31
27
|
@materialized = false
|
32
|
-
@delegate_hash =
|
28
|
+
@delegate_hash = delegate_hash
|
29
|
+
@default_attributes = default_attributes
|
33
30
|
end
|
34
31
|
|
35
32
|
def key?(key)
|
@@ -76,9 +73,31 @@ module ActiveRecord
|
|
76
73
|
end
|
77
74
|
end
|
78
75
|
|
76
|
+
def marshal_dump
|
77
|
+
[@types, @values, @additional_types, @default_attributes, @delegate_hash]
|
78
|
+
end
|
79
|
+
|
80
|
+
def marshal_load(values)
|
81
|
+
if values.is_a?(Hash)
|
82
|
+
empty_hash = {}.freeze
|
83
|
+
initialize(empty_hash, empty_hash, empty_hash, empty_hash, values)
|
84
|
+
@materialized = true
|
85
|
+
else
|
86
|
+
initialize(*values)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def encode_with(coder)
|
91
|
+
coder["delegate_hash"] = materialize
|
92
|
+
end
|
93
|
+
|
94
|
+
def init_with(coder)
|
95
|
+
marshal_load(coder["delegate_hash"])
|
96
|
+
end
|
97
|
+
|
79
98
|
protected
|
80
99
|
|
81
|
-
attr_reader :types, :values, :additional_types, :delegate_hash
|
100
|
+
attr_reader :types, :values, :additional_types, :delegate_hash, :default_attributes
|
82
101
|
|
83
102
|
def materialize
|
84
103
|
unless @materialized
|
@@ -101,7 +120,12 @@ module ActiveRecord
|
|
101
120
|
if value_present
|
102
121
|
delegate_hash[name] = Attribute.from_database(name, value, type)
|
103
122
|
elsif types.key?(name)
|
104
|
-
|
123
|
+
attr = default_attributes[name]
|
124
|
+
if attr
|
125
|
+
delegate_hash[name] = attr.dup
|
126
|
+
else
|
127
|
+
delegate_hash[name] = Attribute.uninitialized(name, type)
|
128
|
+
end
|
105
129
|
end
|
106
130
|
end
|
107
131
|
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+ (
|
37
|
+
# +array+ (PostgreSQL only) specifies that the type should be an array (see the
|
38
38
|
# examples below).
|
39
39
|
#
|
40
|
-
# +range+ (
|
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
|
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
|
-
|
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
|
-
|
348
|
-
|
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
|
-
|
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
|
|
data/lib/active_record/base.rb
CHANGED
@@ -8,17 +8,27 @@ module ActiveRecord
|
|
8
8
|
if collection.loaded?
|
9
9
|
size = collection.size
|
10
10
|
if size > 0
|
11
|
-
timestamp = collection.max_by(×tamp_column).
|
11
|
+
timestamp = collection.max_by(×tamp_column)._read_attribute(timestamp_column)
|
12
12
|
end
|
13
13
|
else
|
14
14
|
column_type = type_for_attribute(timestamp_column.to_s)
|
15
15
|
column = "#{connection.quote_table_name(collection.table_name)}.#{connection.quote_column_name(timestamp_column)}"
|
16
|
+
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
|
16
17
|
|
17
|
-
|
18
|
-
.
|
19
|
-
.
|
20
|
-
|
21
|
-
|
18
|
+
if collection.limit_value || collection.offset_value
|
19
|
+
query = collection.spawn
|
20
|
+
query.select_values = [column]
|
21
|
+
subquery_alias = "subquery_for_cache_key"
|
22
|
+
subquery_column = "#{subquery_alias}.#{timestamp_column}"
|
23
|
+
subquery = query.arel.as(subquery_alias)
|
24
|
+
arel = Arel::SelectManager.new(query.engine).project(select_values % subquery_column).from(subquery)
|
25
|
+
else
|
26
|
+
query = collection.unscope(:order)
|
27
|
+
query.select_values = [select_values % column]
|
28
|
+
arel = query.arel
|
29
|
+
end
|
30
|
+
|
31
|
+
result = connection.select_one(arel, nil, query.bound_attributes)
|
22
32
|
|
23
33
|
if result.blank?
|
24
34
|
size = 0
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
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
|
-
|
668
|
+
@threads_blocking_new_connections += 1
|
681
669
|
end
|
670
|
+
|
682
671
|
yield
|
683
672
|
ensure
|
684
|
-
|
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 @
|
744
|
+
if @threads_blocking_new_connections.zero? && (@connections.size + @now_connecting) < @size
|
737
745
|
@now_connecting += 1
|
738
746
|
end
|
739
747
|
end
|
@@ -927,7 +935,7 @@ module ActiveRecord
|
|
927
935
|
end
|
928
936
|
|
929
937
|
def pool_from_any_process_for(spec_name)
|
930
|
-
owner_to_pool = @owner_to_pool.values.find { |v| v[spec_name] }
|
938
|
+
owner_to_pool = @owner_to_pool.values.reverse.find { |v| v[spec_name] }
|
931
939
|
owner_to_pool && owner_to_pool[spec_name]
|
932
940
|
end
|
933
941
|
end
|
@@ -244,7 +244,7 @@ module ActiveRecord
|
|
244
244
|
end
|
245
245
|
|
246
246
|
def reset_transaction #:nodoc:
|
247
|
-
@transaction_manager = TransactionManager.new(self)
|
247
|
+
@transaction_manager = ConnectionAdapters::TransactionManager.new(self)
|
248
248
|
end
|
249
249
|
|
250
250
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|