activerecord 7.1.1 → 7.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +496 -0
- data/README.rdoc +1 -0
- data/lib/active_record/associations/association.rb +2 -1
- data/lib/active_record/associations/belongs_to_association.rb +4 -4
- data/lib/active_record/associations/collection_association.rb +4 -4
- data/lib/active_record/associations/has_many_association.rb +2 -2
- data/lib/active_record/associations/has_one_association.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +10 -12
- data/lib/active_record/associations/preloader/association.rb +4 -1
- data/lib/active_record/associations.rb +21 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +15 -11
- data/lib/active_record/attribute_methods/read.rb +3 -3
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +47 -7
- data/lib/active_record/autosave_association.rb +5 -2
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +19 -9
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +8 -4
- data/lib/active_record/connection_adapters/abstract_adapter.rb +27 -19
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +37 -13
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +3 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +32 -33
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +1 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +25 -21
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +49 -10
- data/lib/active_record/counter_cache.rb +7 -3
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/hash_config.rb +6 -2
- data/lib/active_record/delegated_type.rb +7 -7
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/encryption/encryptable_record.rb +7 -1
- data/lib/active_record/encryption/encrypted_attribute_type.rb +6 -2
- data/lib/active_record/encryption/extended_deterministic_queries.rb +0 -15
- data/lib/active_record/encryption/scheme.rb +8 -4
- data/lib/active_record/encryption.rb +2 -0
- data/lib/active_record/enum.rb +6 -9
- data/lib/active_record/errors.rb +5 -4
- data/lib/active_record/fixtures.rb +16 -0
- data/lib/active_record/future_result.rb +10 -0
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +3 -3
- data/lib/active_record/internal_metadata.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/middleware/database_selector.rb +1 -1
- data/lib/active_record/migration/compatibility.rb +14 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +9 -5
- data/lib/active_record/model_schema.rb +12 -7
- data/lib/active_record/nested_attributes.rb +16 -5
- data/lib/active_record/normalization.rb +8 -0
- data/lib/active_record/persistence.rb +6 -5
- data/lib/active_record/promise.rb +1 -1
- data/lib/active_record/query_cache.rb +1 -1
- data/lib/active_record/query_logs_formatter.rb +1 -1
- data/lib/active_record/railtie.rb +14 -14
- data/lib/active_record/railties/controller_runtime.rb +2 -1
- data/lib/active_record/railties/databases.rake +7 -7
- data/lib/active_record/reflection.rb +21 -3
- data/lib/active_record/relation/calculations.rb +28 -1
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +6 -1
- data/lib/active_record/relation/query_methods.rb +21 -7
- data/lib/active_record/relation.rb +30 -5
- data/lib/active_record/result.rb +1 -1
- data/lib/active_record/runtime_registry.rb +15 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/secure_token.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +35 -13
- data/lib/active_record/test_fixtures.rb +1 -0
- data/lib/active_record/timestamp.rb +3 -1
- data/lib/active_record.rb +2 -2
- data/lib/arel/nodes/homogeneous_in.rb +1 -1
- data/lib/arel/tree_manager.rb +5 -1
- data/lib/arel/visitors/to_sql.rb +2 -1
- metadata +14 -13
|
@@ -17,11 +17,12 @@ module ActiveRecord
|
|
|
17
17
|
def eql?(other)
|
|
18
18
|
association_key_name == other.association_key_name &&
|
|
19
19
|
scope.table_name == other.scope.table_name &&
|
|
20
|
+
scope.connection_specification_name == other.scope.connection_specification_name &&
|
|
20
21
|
scope.values_for_queries == other.scope.values_for_queries
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def hash
|
|
24
|
-
[association_key_name, scope.table_name, scope.values_for_queries].hash
|
|
25
|
+
[association_key_name, scope.table_name, scope.connection_specification_name, scope.values_for_queries].hash
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def records_for(loaders)
|
|
@@ -38,6 +39,8 @@ module ActiveRecord
|
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
def load_records_for_keys(keys, &block)
|
|
42
|
+
return [] if keys.empty?
|
|
43
|
+
|
|
41
44
|
if association_key_name.is_a?(Array)
|
|
42
45
|
query_constraints = Hash.new { |hsh, key| hsh[key] = Set.new }
|
|
43
46
|
|
|
@@ -1050,7 +1050,7 @@ module ActiveRecord
|
|
|
1050
1050
|
# query per addressable type.
|
|
1051
1051
|
# For example, if all the addressables are either of class Person or Company, then a total
|
|
1052
1052
|
# of 3 queries will be executed. The list of addressable types to load is determined on
|
|
1053
|
-
# the back of the addresses loaded. This is not supported if Active Record has to
|
|
1053
|
+
# the back of the addresses loaded. This is not supported if Active Record has to fall back
|
|
1054
1054
|
# to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError.
|
|
1055
1055
|
# The reason is that the parent model's type is a column value so its corresponding table
|
|
1056
1056
|
# name cannot be put in the +FROM+/+JOIN+ clauses of that query.
|
|
@@ -1339,7 +1339,7 @@ module ActiveRecord
|
|
|
1339
1339
|
# Returns a Relation of all of the associated objects, forcing a database read.
|
|
1340
1340
|
# An empty Relation is returned if none are found.
|
|
1341
1341
|
#
|
|
1342
|
-
#
|
|
1342
|
+
# ==== Example
|
|
1343
1343
|
#
|
|
1344
1344
|
# class Firm < ActiveRecord::Base
|
|
1345
1345
|
# has_many :clients
|
|
@@ -1369,7 +1369,7 @@ module ActiveRecord
|
|
|
1369
1369
|
#
|
|
1370
1370
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
|
1371
1371
|
#
|
|
1372
|
-
#
|
|
1372
|
+
# ==== Scopes
|
|
1373
1373
|
#
|
|
1374
1374
|
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
|
1375
1375
|
# lambda) to retrieve a specific set of records or customize the generated
|
|
@@ -1380,7 +1380,7 @@ module ActiveRecord
|
|
|
1380
1380
|
# has_many :employees, -> { joins(:address) }
|
|
1381
1381
|
# has_many :posts, ->(blog) { where("max_post_length > ?", blog.max_post_length) }
|
|
1382
1382
|
#
|
|
1383
|
-
#
|
|
1383
|
+
# ==== Extensions
|
|
1384
1384
|
#
|
|
1385
1385
|
# The +extension+ argument allows you to pass a block into a has_many
|
|
1386
1386
|
# association. This is useful for adding new finders, creators, and other
|
|
@@ -1394,7 +1394,7 @@ module ActiveRecord
|
|
|
1394
1394
|
# end
|
|
1395
1395
|
# end
|
|
1396
1396
|
#
|
|
1397
|
-
#
|
|
1397
|
+
# ==== Options
|
|
1398
1398
|
# [+:class_name+]
|
|
1399
1399
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
1400
1400
|
# from the association name. So <tt>has_many :products</tt> will by default be linked
|
|
@@ -1506,6 +1506,11 @@ module ActiveRecord
|
|
|
1506
1506
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1507
1507
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1508
1508
|
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
|
1509
|
+
# [+:index_errors+]
|
|
1510
|
+
# Enables differentiation of multiple validation errors from the association records, by including
|
|
1511
|
+
# an index in the error attribute name, e.g. +roles[2].level+.
|
|
1512
|
+
# The index is based on association order, i.e. database order, with yet to be
|
|
1513
|
+
# persisted new records placed at the end.
|
|
1509
1514
|
#
|
|
1510
1515
|
# Option examples:
|
|
1511
1516
|
# has_many :comments, -> { order("posted_on") }
|
|
@@ -1519,6 +1524,7 @@ module ActiveRecord
|
|
|
1519
1524
|
# has_many :subscribers, through: :subscriptions, disable_joins: true
|
|
1520
1525
|
# has_many :comments, strict_loading: true
|
|
1521
1526
|
# has_many :comments, query_constraints: [:blog_id, :post_id]
|
|
1527
|
+
# has_many :comments, index_errors: true
|
|
1522
1528
|
def has_many(name, scope = nil, **options, &extension)
|
|
1523
1529
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
|
1524
1530
|
Reflection.add_reflection self, name, reflection
|
|
@@ -1556,7 +1562,7 @@ module ActiveRecord
|
|
|
1556
1562
|
# [<tt>reset_association</tt>]
|
|
1557
1563
|
# Unloads the associated object. The next access will query it from the database.
|
|
1558
1564
|
#
|
|
1559
|
-
#
|
|
1565
|
+
# ==== Example
|
|
1560
1566
|
#
|
|
1561
1567
|
# class Account < ActiveRecord::Base
|
|
1562
1568
|
# has_one :beneficiary
|
|
@@ -1575,7 +1581,7 @@ module ActiveRecord
|
|
|
1575
1581
|
# account.reload_beneficiary
|
|
1576
1582
|
# account.reset_beneficiary
|
|
1577
1583
|
#
|
|
1578
|
-
#
|
|
1584
|
+
# ==== Scopes
|
|
1579
1585
|
#
|
|
1580
1586
|
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
|
1581
1587
|
# lambda) to retrieve a specific record or customize the generated query
|
|
@@ -1586,7 +1592,7 @@ module ActiveRecord
|
|
|
1586
1592
|
# has_one :employer, -> { joins(:company) }
|
|
1587
1593
|
# has_one :latest_post, ->(blog) { where("created_at > ?", blog.enabled_at) }
|
|
1588
1594
|
#
|
|
1589
|
-
#
|
|
1595
|
+
# ==== Options
|
|
1590
1596
|
#
|
|
1591
1597
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
|
1592
1598
|
#
|
|
@@ -1745,7 +1751,7 @@ module ActiveRecord
|
|
|
1745
1751
|
# [<tt>association_previously_changed?</tt>]
|
|
1746
1752
|
# Returns true if the previous save updated the association to reference a new associate object.
|
|
1747
1753
|
#
|
|
1748
|
-
#
|
|
1754
|
+
# ==== Example
|
|
1749
1755
|
#
|
|
1750
1756
|
# class Post < ActiveRecord::Base
|
|
1751
1757
|
# belongs_to :author
|
|
@@ -1766,7 +1772,7 @@ module ActiveRecord
|
|
|
1766
1772
|
# post.author_changed?
|
|
1767
1773
|
# post.author_previously_changed?
|
|
1768
1774
|
#
|
|
1769
|
-
#
|
|
1775
|
+
# ==== Scopes
|
|
1770
1776
|
#
|
|
1771
1777
|
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
|
1772
1778
|
# lambda) to retrieve a specific record or customize the generated query
|
|
@@ -1777,7 +1783,7 @@ module ActiveRecord
|
|
|
1777
1783
|
# belongs_to :user, -> { joins(:friends) }
|
|
1778
1784
|
# belongs_to :level, ->(game) { where("game_level > ?", game.current_level) }
|
|
1779
1785
|
#
|
|
1780
|
-
#
|
|
1786
|
+
# ==== Options
|
|
1781
1787
|
#
|
|
1782
1788
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
|
1783
1789
|
#
|
|
@@ -1964,7 +1970,7 @@ module ActiveRecord
|
|
|
1964
1970
|
# Returns a Relation of all of the associated objects, forcing a database read.
|
|
1965
1971
|
# An empty Relation is returned if none are found.
|
|
1966
1972
|
#
|
|
1967
|
-
#
|
|
1973
|
+
# ==== Example
|
|
1968
1974
|
#
|
|
1969
1975
|
# class Developer < ActiveRecord::Base
|
|
1970
1976
|
# has_and_belongs_to_many :projects
|
|
@@ -1993,7 +1999,7 @@ module ActiveRecord
|
|
|
1993
1999
|
#
|
|
1994
2000
|
# The declaration may include an +options+ hash to specialize the behavior of the association.
|
|
1995
2001
|
#
|
|
1996
|
-
#
|
|
2002
|
+
# ==== Scopes
|
|
1997
2003
|
#
|
|
1998
2004
|
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
|
1999
2005
|
# lambda) to retrieve a specific set of records or customize the generated
|
|
@@ -2005,7 +2011,7 @@ module ActiveRecord
|
|
|
2005
2011
|
# where("default_category = ?", post.default_category)
|
|
2006
2012
|
# }
|
|
2007
2013
|
#
|
|
2008
|
-
#
|
|
2014
|
+
# ==== Extensions
|
|
2009
2015
|
#
|
|
2010
2016
|
# The +extension+ argument allows you to pass a block into a
|
|
2011
2017
|
# has_and_belongs_to_many association. This is useful for adding new
|
|
@@ -2020,7 +2026,7 @@ module ActiveRecord
|
|
|
2020
2026
|
# end
|
|
2021
2027
|
# end
|
|
2022
2028
|
#
|
|
2023
|
-
#
|
|
2029
|
+
# ==== Options
|
|
2024
2030
|
#
|
|
2025
2031
|
# [+:class_name+]
|
|
2026
2032
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
|
14
14
|
# class Person < ActiveRecord::Base
|
|
15
15
|
# end
|
|
16
16
|
#
|
|
17
|
-
# person = Person.create(name: "
|
|
17
|
+
# person = Person.create(name: "Allison")
|
|
18
18
|
# person.changed? # => false
|
|
19
19
|
#
|
|
20
20
|
# Change the name:
|
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
|
31
31
|
# person.name_in_database # => "Alice"
|
|
32
32
|
# person.saved_change_to_name? # => true
|
|
33
33
|
# person.saved_change_to_name # => ["Allison", "Alice"]
|
|
34
|
-
# person.
|
|
34
|
+
# person.name_before_last_save # => "Allison"
|
|
35
35
|
#
|
|
36
36
|
# Similar to ActiveModel::Dirty, methods can be invoked as
|
|
37
37
|
# +saved_change_to_name?+ or by passing an argument to the generic method
|
|
@@ -76,11 +76,13 @@ module ActiveRecord
|
|
|
76
76
|
#
|
|
77
77
|
# ==== Options
|
|
78
78
|
#
|
|
79
|
-
# +from+
|
|
80
|
-
#
|
|
79
|
+
# [+from+]
|
|
80
|
+
# When specified, this method will return false unless the original
|
|
81
|
+
# value is equal to the given value.
|
|
81
82
|
#
|
|
82
|
-
# +to+
|
|
83
|
-
#
|
|
83
|
+
# [+to+]
|
|
84
|
+
# When specified, this method will return false unless the value will be
|
|
85
|
+
# changed to the given value.
|
|
84
86
|
def saved_change_to_attribute?(attr_name, **options)
|
|
85
87
|
mutations_before_last_save.changed?(attr_name.to_s, **options)
|
|
86
88
|
end
|
|
@@ -126,11 +128,13 @@ module ActiveRecord
|
|
|
126
128
|
#
|
|
127
129
|
# ==== Options
|
|
128
130
|
#
|
|
129
|
-
# +from+
|
|
130
|
-
#
|
|
131
|
+
# [+from+]
|
|
132
|
+
# When specified, this method will return false unless the original
|
|
133
|
+
# value is equal to the given value.
|
|
131
134
|
#
|
|
132
|
-
# +to+
|
|
133
|
-
#
|
|
135
|
+
# [+to+]
|
|
136
|
+
# When specified, this method will return false unless the value will be
|
|
137
|
+
# changed to the given value.
|
|
134
138
|
def will_save_change_to_attribute?(attr_name, **options)
|
|
135
139
|
mutations_from_database.changed?(attr_name.to_s, **options)
|
|
136
140
|
end
|
|
@@ -247,7 +251,7 @@ module ActiveRecord
|
|
|
247
251
|
changed_attribute_names_to_save
|
|
248
252
|
else
|
|
249
253
|
attribute_names.reject do |attr_name|
|
|
250
|
-
if column_for_attribute(attr_name).
|
|
254
|
+
if column_for_attribute(attr_name).auto_populated?
|
|
251
255
|
!attribute_changed?(attr_name)
|
|
252
256
|
end
|
|
253
257
|
end
|
|
@@ -8,11 +8,11 @@ module ActiveRecord
|
|
|
8
8
|
|
|
9
9
|
module ClassMethods # :nodoc:
|
|
10
10
|
private
|
|
11
|
-
def define_method_attribute(
|
|
11
|
+
def define_method_attribute(canonical_name, owner:, as: canonical_name)
|
|
12
12
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
|
13
|
-
owner,
|
|
13
|
+
owner, canonical_name
|
|
14
14
|
) do |temp_method_name, attr_name_expr|
|
|
15
|
-
owner.define_cached_method(
|
|
15
|
+
owner.define_cached_method(temp_method_name, as: as, namespace: :active_record) do |batch|
|
|
16
16
|
batch <<
|
|
17
17
|
"def #{temp_method_name}" <<
|
|
18
18
|
" _read_attribute(#{attr_name_expr}) { |n| missing_attribute(n, caller) }" <<
|
|
@@ -12,11 +12,11 @@ module ActiveRecord
|
|
|
12
12
|
|
|
13
13
|
module ClassMethods # :nodoc:
|
|
14
14
|
private
|
|
15
|
-
def define_method_attribute=(
|
|
15
|
+
def define_method_attribute=(canonical_name, owner:, as: canonical_name)
|
|
16
16
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
|
17
|
-
owner,
|
|
17
|
+
owner, canonical_name, writer: true,
|
|
18
18
|
) do |temp_method_name, attr_name_expr|
|
|
19
|
-
owner.define_cached_method("#{
|
|
19
|
+
owner.define_cached_method(temp_method_name, as: "#{as}=", namespace: :active_record) do |batch|
|
|
20
20
|
batch <<
|
|
21
21
|
"def #{temp_method_name}(value)" <<
|
|
22
22
|
" _write_attribute(#{attr_name_expr}, value)" <<
|
|
@@ -34,7 +34,7 @@ module ActiveRecord
|
|
|
34
34
|
Base.private_instance_methods -
|
|
35
35
|
Base.superclass.instance_methods -
|
|
36
36
|
Base.superclass.private_instance_methods +
|
|
37
|
-
%i[__id__ dup freeze frozen? hash
|
|
37
|
+
%i[__id__ dup freeze frozen? hash class clone]
|
|
38
38
|
).map { |m| -m.to_s }.to_set.freeze
|
|
39
39
|
end
|
|
40
40
|
end
|
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
|
66
66
|
|
|
67
67
|
def generate_alias_attributes # :nodoc:
|
|
68
68
|
superclass.generate_alias_attributes unless superclass == Base
|
|
69
|
-
return if @alias_attributes_mass_generated
|
|
69
|
+
return false if @alias_attributes_mass_generated
|
|
70
70
|
|
|
71
71
|
generated_attribute_methods.synchronize do
|
|
72
72
|
return if @alias_attributes_mass_generated
|
|
@@ -80,12 +80,19 @@ module ActiveRecord
|
|
|
80
80
|
|
|
81
81
|
@alias_attributes_mass_generated = true
|
|
82
82
|
end
|
|
83
|
+
true
|
|
83
84
|
end
|
|
84
85
|
|
|
85
|
-
def
|
|
86
|
+
def generate_alias_attribute_methods(code_generator, new_name, old_name) # :nodoc:
|
|
87
|
+
attribute_method_patterns.each do |pattern|
|
|
88
|
+
alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
|
|
89
|
+
end
|
|
90
|
+
attribute_method_patterns_cache.clear
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def alias_attribute_method_definition(code_generator, pattern, new_name, old_name) # :nodoc:
|
|
86
94
|
method_name = pattern.method_name(new_name).to_s
|
|
87
95
|
target_name = pattern.method_name(old_name).to_s
|
|
88
|
-
parameters = pattern.parameters
|
|
89
96
|
old_name = old_name.to_s
|
|
90
97
|
|
|
91
98
|
method_defined = method_defined?(target_name) || private_method_defined?(target_name)
|
|
@@ -115,9 +122,7 @@ module ActiveRecord
|
|
|
115
122
|
)
|
|
116
123
|
super
|
|
117
124
|
else
|
|
118
|
-
|
|
119
|
-
namespace: :proxy_alias_attribute
|
|
120
|
-
)
|
|
125
|
+
define_attribute_method_pattern(pattern, old_name, owner: code_generator, as: new_name, override: true)
|
|
121
126
|
end
|
|
122
127
|
end
|
|
123
128
|
|
|
@@ -133,6 +138,11 @@ module ActiveRecord
|
|
|
133
138
|
super(attribute_names)
|
|
134
139
|
@attribute_methods_generated = true
|
|
135
140
|
end
|
|
141
|
+
true
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def attribute_methods_generated? # :nodoc:
|
|
145
|
+
@attribute_methods_generated && @alias_attributes_mass_generated
|
|
136
146
|
end
|
|
137
147
|
|
|
138
148
|
def undefine_attribute_methods # :nodoc:
|
|
@@ -459,6 +469,36 @@ module ActiveRecord
|
|
|
459
469
|
end
|
|
460
470
|
|
|
461
471
|
private
|
|
472
|
+
def respond_to_missing?(name, include_private = false)
|
|
473
|
+
if self.class.define_attribute_methods
|
|
474
|
+
# Some methods weren't defined yet.
|
|
475
|
+
return true if self.class.method_defined?(name)
|
|
476
|
+
return true if include_private && self.class.private_method_defined?(name)
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
super
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def method_missing(name, ...)
|
|
483
|
+
unless self.class.attribute_methods_generated?
|
|
484
|
+
if self.class.method_defined?(name)
|
|
485
|
+
# The method is explicitly defined in the model, but calls a generated
|
|
486
|
+
# method with super. So we must resume the call chain at the right setp.
|
|
487
|
+
last_method = method(name)
|
|
488
|
+
last_method = last_method.super_method while last_method.super_method
|
|
489
|
+
self.class.define_attribute_methods
|
|
490
|
+
if last_method.super_method
|
|
491
|
+
return last_method.super_method.call(...)
|
|
492
|
+
end
|
|
493
|
+
elsif self.class.define_attribute_methods | self.class.generate_alias_attributes
|
|
494
|
+
# Some attribute methods weren't generated yet, we retry the call
|
|
495
|
+
return public_send(name, ...)
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
super
|
|
500
|
+
end
|
|
501
|
+
|
|
462
502
|
def attribute_method?(attr_name)
|
|
463
503
|
# We check defined? because Syck calls respond_to? before actually calling initialize.
|
|
464
504
|
defined?(@attributes) && @attributes.key?(attr_name)
|
|
@@ -441,7 +441,9 @@ module ActiveRecord
|
|
|
441
441
|
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
|
|
442
442
|
def save_has_one_association(reflection)
|
|
443
443
|
association = association_instance_get(reflection.name)
|
|
444
|
-
|
|
444
|
+
return unless association && association.loaded?
|
|
445
|
+
|
|
446
|
+
record = association.load_target
|
|
445
447
|
|
|
446
448
|
if record && !record.destroyed?
|
|
447
449
|
autosave = reflection.options[:autosave]
|
|
@@ -458,7 +460,8 @@ module ActiveRecord
|
|
|
458
460
|
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
|
459
461
|
|
|
460
462
|
primary_key_foreign_key_pairs.each do |primary_key, foreign_key|
|
|
461
|
-
|
|
463
|
+
association_id = _read_attribute(primary_key)
|
|
464
|
+
record[foreign_key] = association_id unless record[foreign_key] == association_id
|
|
462
465
|
end
|
|
463
466
|
association.set_inverse_instance(record)
|
|
464
467
|
end
|
|
@@ -241,8 +241,8 @@ module ActiveRecord
|
|
|
241
241
|
#
|
|
242
242
|
# config.active_record.run_after_transaction_callbacks_in_order_defined = false
|
|
243
243
|
#
|
|
244
|
-
#
|
|
245
|
-
# are defined, just like the example above.
|
|
244
|
+
# When set to +true+ (the default from \Rails 7.1), callbacks are executed in the order they
|
|
245
|
+
# are defined, just like the example above. When set to +false+, the order is reversed, so
|
|
246
246
|
# +do_something_else+ is executed before +log_children+.
|
|
247
247
|
#
|
|
248
248
|
# == \Transactions
|
|
@@ -58,12 +58,10 @@ module ActiveRecord
|
|
|
58
58
|
# Connections can be obtained and used from a connection pool in several
|
|
59
59
|
# ways:
|
|
60
60
|
#
|
|
61
|
-
# 1. Simply use {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling.connection]
|
|
62
|
-
#
|
|
63
|
-
# earlier (pre-connection-pooling). Eventually, when you're done with
|
|
64
|
-
# the connection(s) and wish it to be returned to the pool, you call
|
|
61
|
+
# 1. Simply use {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling.connection].
|
|
62
|
+
# When you're done with the connection(s) and wish it to be returned to the pool, you call
|
|
65
63
|
# {ActiveRecord::Base.connection_handler.clear_active_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_active_connections!].
|
|
66
|
-
# This
|
|
64
|
+
# This is the default behavior for Active Record when used in conjunction with
|
|
67
65
|
# Action Pack's request handling cycle.
|
|
68
66
|
# 2. Manually check out a connection from the pool with
|
|
69
67
|
# {ActiveRecord::Base.connection_pool.checkout}[rdoc-ref:#checkout]. You are responsible for
|
|
@@ -465,8 +463,7 @@ module ActiveRecord
|
|
|
465
463
|
@available.num_waiting
|
|
466
464
|
end
|
|
467
465
|
|
|
468
|
-
#
|
|
469
|
-
# Example:
|
|
466
|
+
# Returns the connection pool's usage statistic.
|
|
470
467
|
#
|
|
471
468
|
# ActiveRecord::Base.connection_pool.stat # => { size: 15, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout: 5 }
|
|
472
469
|
def stat
|
|
@@ -658,7 +655,13 @@ module ActiveRecord
|
|
|
658
655
|
conn
|
|
659
656
|
else
|
|
660
657
|
reap
|
|
661
|
-
|
|
658
|
+
# Retry after reaping, which may return an available connection,
|
|
659
|
+
# remove an inactive connection, or both
|
|
660
|
+
if conn = @available.poll || try_to_checkout_new_connection
|
|
661
|
+
conn
|
|
662
|
+
else
|
|
663
|
+
@available.poll(checkout_timeout)
|
|
664
|
+
end
|
|
662
665
|
end
|
|
663
666
|
end
|
|
664
667
|
|
|
@@ -672,7 +675,14 @@ module ActiveRecord
|
|
|
672
675
|
def new_connection
|
|
673
676
|
connection = Base.public_send(db_config.adapter_method, db_config.configuration_hash)
|
|
674
677
|
connection.pool = self
|
|
675
|
-
|
|
678
|
+
|
|
679
|
+
begin
|
|
680
|
+
connection.check_version
|
|
681
|
+
rescue
|
|
682
|
+
connection.disconnect!
|
|
683
|
+
raise
|
|
684
|
+
end
|
|
685
|
+
|
|
676
686
|
connection
|
|
677
687
|
rescue ConnectionNotEstablished => ex
|
|
678
688
|
raise ex.set_pool(self)
|
|
@@ -189,8 +189,10 @@ module ActiveRecord
|
|
|
189
189
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
|
|
190
190
|
sql, binds = to_sql_and_binds(arel, binds)
|
|
191
191
|
value = exec_insert(sql, name, binds, pk, sequence_name, returning: returning)
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
|
|
193
|
+
return returning_column_values(value) unless returning.nil?
|
|
194
|
+
|
|
195
|
+
id_value || last_inserted_id(value)
|
|
194
196
|
end
|
|
195
197
|
alias create insert
|
|
196
198
|
|
|
@@ -627,7 +629,7 @@ module ActiveRecord
|
|
|
627
629
|
|
|
628
630
|
result = internal_exec_query(sql, name, binds, prepare: prepare)
|
|
629
631
|
if async
|
|
630
|
-
FutureResult
|
|
632
|
+
FutureResult.wrap(result)
|
|
631
633
|
else
|
|
632
634
|
result
|
|
633
635
|
end
|
|
@@ -106,7 +106,8 @@ module ActiveRecord
|
|
|
106
106
|
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
|
107
107
|
|
|
108
108
|
if async
|
|
109
|
-
lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async)
|
|
109
|
+
result = lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async)
|
|
110
|
+
FutureResult.wrap(result)
|
|
110
111
|
else
|
|
111
112
|
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable, async: async) }
|
|
112
113
|
end
|
|
@@ -963,7 +963,11 @@ module ActiveRecord
|
|
|
963
963
|
def index_name(table_name, options) # :nodoc:
|
|
964
964
|
if Hash === options
|
|
965
965
|
if options[:column]
|
|
966
|
-
|
|
966
|
+
if options[:_uses_legacy_index_name]
|
|
967
|
+
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
|
968
|
+
else
|
|
969
|
+
generate_index_name(table_name, options[:column])
|
|
970
|
+
end
|
|
967
971
|
elsif options[:name]
|
|
968
972
|
options[:name]
|
|
969
973
|
else
|
|
@@ -1636,11 +1640,11 @@ module ActiveRecord
|
|
|
1636
1640
|
end
|
|
1637
1641
|
end
|
|
1638
1642
|
|
|
1639
|
-
def rename_table_indexes(table_name, new_name)
|
|
1643
|
+
def rename_table_indexes(table_name, new_name, **options)
|
|
1640
1644
|
indexes(new_name).each do |index|
|
|
1641
|
-
generated_index_name = index_name(table_name, column: index.columns)
|
|
1645
|
+
generated_index_name = index_name(table_name, column: index.columns, **options)
|
|
1642
1646
|
if generated_index_name == index.name
|
|
1643
|
-
rename_index new_name, generated_index_name, index_name(new_name, column: index.columns)
|
|
1647
|
+
rename_index new_name, generated_index_name, index_name(new_name, column: index.columns, **options)
|
|
1644
1648
|
end
|
|
1645
1649
|
end
|
|
1646
1650
|
end
|
|
@@ -711,13 +711,14 @@ module ActiveRecord
|
|
|
711
711
|
end
|
|
712
712
|
end
|
|
713
713
|
|
|
714
|
-
|
|
715
714
|
# Disconnects from the database if already connected. Otherwise, this
|
|
716
715
|
# method does nothing.
|
|
717
716
|
def disconnect!
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
717
|
+
@lock.synchronize do
|
|
718
|
+
clear_cache!(new_connection: true)
|
|
719
|
+
reset_transaction
|
|
720
|
+
@raw_connection_dirty = false
|
|
721
|
+
end
|
|
721
722
|
end
|
|
722
723
|
|
|
723
724
|
# Immediately forget this connection ever existed. Unlike disconnect!,
|
|
@@ -773,19 +774,17 @@ module ActiveRecord
|
|
|
773
774
|
# is no longer active, then this method will reconnect to the database.
|
|
774
775
|
def verify!
|
|
775
776
|
unless active?
|
|
776
|
-
|
|
777
|
-
@
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
return
|
|
784
|
-
end
|
|
777
|
+
@lock.synchronize do
|
|
778
|
+
if @unconfigured_connection
|
|
779
|
+
@raw_connection = @unconfigured_connection
|
|
780
|
+
@unconfigured_connection = nil
|
|
781
|
+
configure_connection
|
|
782
|
+
@verified = true
|
|
783
|
+
return
|
|
785
784
|
end
|
|
786
|
-
end
|
|
787
785
|
|
|
788
|
-
|
|
786
|
+
reconnect!(restore_transactions: true)
|
|
787
|
+
end
|
|
789
788
|
end
|
|
790
789
|
|
|
791
790
|
@verified = true
|
|
@@ -970,7 +969,11 @@ module ActiveRecord
|
|
|
970
969
|
# If +allow_retry+ is true, a connection-related exception will
|
|
971
970
|
# cause an automatic reconnect and re-run of the block, up to
|
|
972
971
|
# the connection's configured +connection_retries+ setting
|
|
973
|
-
# and the configured +retry_deadline+ limit.
|
|
972
|
+
# and the configured +retry_deadline+ limit. (Note that when
|
|
973
|
+
# +allow_retry+ is true, it's possible to return without having marked
|
|
974
|
+
# the connection as verified. If the block is guaranteed to exercise the
|
|
975
|
+
# connection, consider calling `verified!` to avoid needless
|
|
976
|
+
# verification queries in subsequent calls.)
|
|
974
977
|
#
|
|
975
978
|
# If +materialize_transactions+ is false, the block will be run without
|
|
976
979
|
# ensuring virtual transactions have been materialized in the DB
|
|
@@ -1021,9 +1024,7 @@ module ActiveRecord
|
|
|
1021
1024
|
end
|
|
1022
1025
|
|
|
1023
1026
|
begin
|
|
1024
|
-
|
|
1025
|
-
@verified = true
|
|
1026
|
-
result
|
|
1027
|
+
yield @raw_connection
|
|
1027
1028
|
rescue => original_exception
|
|
1028
1029
|
translated_exception = translate_exception_class(original_exception, nil, nil)
|
|
1029
1030
|
invalidate_transaction(translated_exception)
|
|
@@ -1058,6 +1059,13 @@ module ActiveRecord
|
|
|
1058
1059
|
end
|
|
1059
1060
|
end
|
|
1060
1061
|
|
|
1062
|
+
# Mark the connection as verified. Call this inside a
|
|
1063
|
+
# `with_raw_connection` block only when the block is guaranteed to
|
|
1064
|
+
# exercise the raw connection.
|
|
1065
|
+
def verified!
|
|
1066
|
+
@verified = true
|
|
1067
|
+
end
|
|
1068
|
+
|
|
1061
1069
|
def retryable_connection_error?(exception)
|
|
1062
1070
|
exception.is_a?(ConnectionNotEstablished) || exception.is_a?(ConnectionFailed)
|
|
1063
1071
|
end
|