activerecord 7.1.5.1 → 7.2.0.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +515 -2445
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +9 -8
- data/lib/active_record/associations/belongs_to_association.rb +14 -7
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +6 -4
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -28
- data/lib/active_record/associations/join_dependency.rb +5 -5
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +33 -16
- data/lib/active_record/attribute_assignment.rb +1 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +1 -1
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +4 -16
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -10
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +60 -71
- data/lib/active_record/attributes.rb +55 -42
- data/lib/active_record/autosave_association.rb +13 -32
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +248 -65
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +159 -74
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/transaction.rb +60 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +18 -46
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +11 -5
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -23
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -13
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -21
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +107 -75
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +12 -6
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +56 -41
- data/lib/active_record/core.rb +53 -37
- data/lib/active_record/counter_cache.rb +18 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +15 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +24 -0
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +2 -2
- data/lib/active_record/encryption/encrypted_attribute_type.rb +22 -2
- data/lib/active_record/encryption/encryptor.rb +17 -2
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption.rb +0 -2
- data/lib/active_record/enum.rb +10 -1
- data/lib/active_record/errors.rb +16 -11
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/marshalling.rb +1 -4
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +85 -76
- data/lib/active_record/model_schema.rb +28 -68
- data/lib/active_record/nested_attributes.rb +13 -16
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +18 -6
- data/lib/active_record/query_logs.rb +15 -0
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +50 -62
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +41 -44
- data/lib/active_record/reflection.rb +90 -35
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +94 -61
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +16 -2
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +196 -57
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +496 -72
- data/lib/active_record/result.rb +31 -44
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +19 -9
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/signed_id.rb +11 -1
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +76 -70
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +81 -91
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +1 -1
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +68 -0
- data/lib/active_record/transactions.rb +43 -14
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +14 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +149 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- metadata +20 -15
@@ -1506,11 +1506,13 @@ 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
|
-
# [
|
1510
|
-
#
|
1511
|
-
# an index in the error attribute name, e.g.
|
1512
|
-
#
|
1509
|
+
# [:index_errors]
|
1510
|
+
# Allows 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
|
+
# When set to +true+, the index is based on association order, i.e. database order, with yet to be
|
1513
1513
|
# persisted new records placed at the end.
|
1514
|
+
# When set to +:nested_attributes_order+, the index is based on the record order received by
|
1515
|
+
# nested attributes setter, when accepts_nested_attributes_for is used.
|
1514
1516
|
#
|
1515
1517
|
# Option examples:
|
1516
1518
|
# has_many :comments, -> { order("posted_on") }
|
@@ -1524,7 +1526,7 @@ module ActiveRecord
|
|
1524
1526
|
# has_many :subscribers, through: :subscriptions, disable_joins: true
|
1525
1527
|
# has_many :comments, strict_loading: true
|
1526
1528
|
# has_many :comments, query_constraints: [:blog_id, :post_id]
|
1527
|
-
# has_many :comments, index_errors:
|
1529
|
+
# has_many :comments, index_errors: :nested_attributes_order
|
1528
1530
|
def has_many(name, scope = nil, **options, &extension)
|
1529
1531
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
1530
1532
|
Reflection.add_reflection self, name, reflection
|
@@ -1667,9 +1669,14 @@ module ActiveRecord
|
|
1667
1669
|
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
1668
1670
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
1669
1671
|
# [+:autosave+]
|
1670
|
-
# If true
|
1671
|
-
# when saving the parent object.
|
1672
|
-
#
|
1672
|
+
# If +true+, always saves the associated object or destroys it if marked for destruction,
|
1673
|
+
# when saving the parent object.
|
1674
|
+
# If +false+, never save or destroy the associated object.
|
1675
|
+
#
|
1676
|
+
# By default, only saves the associated object if it's a new record. Setting this option
|
1677
|
+
# to +true+ also enables validations on the associated object unless explicitly disabled
|
1678
|
+
# with <tt>validate: false</tt>. This is because saving an object with invalid associated
|
1679
|
+
# objects would fail, so any associated objects will go through validation checks.
|
1673
1680
|
#
|
1674
1681
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
1675
1682
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
@@ -1822,15 +1829,25 @@ module ActiveRecord
|
|
1822
1829
|
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
|
1823
1830
|
# is used on the associate class (such as a Post class) - that is the migration for
|
1824
1831
|
# <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
|
1825
|
-
# return the count cached
|
1832
|
+
# return the count cached). You can also specify a custom counter
|
1826
1833
|
# cache column by providing a column name instead of a +true+/+false+ value to this
|
1827
1834
|
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
|
1828
|
-
#
|
1829
|
-
#
|
1830
|
-
#
|
1831
|
-
#
|
1835
|
+
#
|
1836
|
+
# Starting to use counter caches on existing large tables can be troublesome, because the column
|
1837
|
+
# values must be backfilled separately of the column addition (to not lock the table for too long)
|
1838
|
+
# and before the use of +:counter_cache+ (otherwise methods like +size+/+any?+/etc, which use
|
1839
|
+
# counter caches internally, can produce incorrect results). To safely backfill the values while keeping
|
1840
|
+
# counter cache columns updated with the child records creation/removal and to avoid the mentioned methods
|
1841
|
+
# use the possibly incorrect counter cache column values and always get the results from the database,
|
1842
|
+
# use <tt>counter_cache: { active: false }</tt>.
|
1843
|
+
# If you also need to specify a custom column name, use <tt>counter_cache: { active: false, column: :my_custom_counter }</tt>.
|
1844
|
+
#
|
1832
1845
|
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
1833
1846
|
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
|
1847
|
+
# [+:polymorphic+]
|
1848
|
+
# Specify this association is a polymorphic association by passing +true+.
|
1849
|
+
# Note: Since polymorphic associations rely on storing class names in the database, make sure to update the class names in the
|
1850
|
+
# <tt>*_type</tt> polymorphic type column of the corresponding rows.
|
1834
1851
|
# [+:validate+]
|
1835
1852
|
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
1836
1853
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
@@ -1888,7 +1905,7 @@ module ActiveRecord
|
|
1888
1905
|
# belongs_to :user, optional: true
|
1889
1906
|
# belongs_to :account, default: -> { company.account }
|
1890
1907
|
# belongs_to :account, strict_loading: true
|
1891
|
-
#
|
1908
|
+
# belongs_to :note, query_constraints: [:organization_id, :note_id]
|
1892
1909
|
def belongs_to(name, scope = nil, **options)
|
1893
1910
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
1894
1911
|
Reflection.add_reflection self, name, reflection
|
@@ -1911,7 +1928,7 @@ module ActiveRecord
|
|
1911
1928
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
1912
1929
|
# join table with a migration such as this:
|
1913
1930
|
#
|
1914
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[7.
|
1931
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[7.2]
|
1915
1932
|
# def change
|
1916
1933
|
# create_join_table :developers, :projects
|
1917
1934
|
# end
|
@@ -2105,7 +2122,7 @@ module ActiveRecord
|
|
2105
2122
|
end
|
2106
2123
|
|
2107
2124
|
has_many name, scope, **hm_options, &extension
|
2108
|
-
_reflections[name
|
2125
|
+
_reflections[name].parent_reflection = habtm_reflection
|
2109
2126
|
end
|
2110
2127
|
end
|
2111
2128
|
end
|
@@ -2,33 +2,23 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module AttributeAssignment
|
5
|
-
include ActiveModel::AttributeAssignment
|
6
|
-
|
7
5
|
private
|
8
6
|
def _assign_attributes(attributes)
|
9
|
-
multi_parameter_attributes =
|
7
|
+
multi_parameter_attributes = nil
|
10
8
|
|
11
9
|
attributes.each do |k, v|
|
12
10
|
key = k.to_s
|
13
11
|
|
14
12
|
if key.include?("(")
|
15
13
|
(multi_parameter_attributes ||= {})[key] = v
|
16
|
-
elsif v.is_a?(Hash)
|
17
|
-
(nested_parameter_attributes ||= {})[key] = v
|
18
14
|
else
|
19
15
|
_assign_attribute(key, v)
|
20
16
|
end
|
21
17
|
end
|
22
18
|
|
23
|
-
assign_nested_parameter_attributes(nested_parameter_attributes) if nested_parameter_attributes
|
24
19
|
assign_multiparameter_attributes(multi_parameter_attributes) if multi_parameter_attributes
|
25
20
|
end
|
26
21
|
|
27
|
-
# Assign any deferred nested attributes after the base attributes have been set.
|
28
|
-
def assign_nested_parameter_attributes(pairs)
|
29
|
-
pairs.each { |k, v| _assign_attribute(k, v) }
|
30
|
-
end
|
31
|
-
|
32
22
|
# Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
|
33
23
|
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
|
34
24
|
# So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module AttributeMethods
|
5
|
+
module CompositePrimaryKey # :nodoc:
|
6
|
+
# Returns the primary key column's value. If the primary key is composite,
|
7
|
+
# returns an array of the primary key column values.
|
8
|
+
def id
|
9
|
+
if self.class.composite_primary_key?
|
10
|
+
@primary_key.map { |pk| _read_attribute(pk) }
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def primary_key_values_present? # :nodoc:
|
17
|
+
if self.class.composite_primary_key?
|
18
|
+
id.all?
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets the primary key column's value. If the primary key is composite,
|
25
|
+
# raises TypeError when the set value not enumerable.
|
26
|
+
def id=(value)
|
27
|
+
if self.class.composite_primary_key?
|
28
|
+
raise TypeError, "Expected value matching #{self.class.primary_key.inspect}, got #{value.inspect}." unless value.is_a?(Enumerable)
|
29
|
+
@primary_key.zip(value) { |attr, value| _write_attribute(attr, value) }
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Queries the primary key column's value. If the primary key is composite,
|
36
|
+
# all primary key column values must be queryable.
|
37
|
+
def id?
|
38
|
+
if self.class.composite_primary_key?
|
39
|
+
@primary_key.all? { |col| _query_attribute(col) }
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the primary key column's value before type cast. If the primary key is composite,
|
46
|
+
# returns an array of primary key column values before type cast.
|
47
|
+
def id_before_type_cast
|
48
|
+
if self.class.composite_primary_key?
|
49
|
+
@primary_key.map { |col| attribute_before_type_cast(col) }
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the primary key column's previous value. If the primary key is composite,
|
56
|
+
# returns an array of primary key column previous values.
|
57
|
+
def id_was
|
58
|
+
if self.class.composite_primary_key?
|
59
|
+
@primary_key.map { |col| attribute_was(col) }
|
60
|
+
else
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the primary key column's value from the database. If the primary key is composite,
|
66
|
+
# returns an array of primary key column values from database.
|
67
|
+
def id_in_database
|
68
|
+
if self.class.composite_primary_key?
|
69
|
+
@primary_key.map { |col| attribute_in_database(col) }
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def id_for_database # :nodoc:
|
76
|
+
if self.class.composite_primary_key?
|
77
|
+
@primary_key.map { |col| @attributes[col].value_for_database }
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -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_change # => "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
|
@@ -18,74 +18,45 @@ module ActiveRecord
|
|
18
18
|
# Returns the primary key column's value. If the primary key is composite,
|
19
19
|
# returns an array of the primary key column values.
|
20
20
|
def id
|
21
|
-
|
22
|
-
|
23
|
-
@primary_key.map { |pk| _read_attribute(pk) }
|
21
|
+
_read_attribute(@primary_key)
|
24
22
|
end
|
25
23
|
|
26
24
|
def primary_key_values_present? # :nodoc:
|
27
|
-
return id.all? if self.class.composite_primary_key?
|
28
|
-
|
29
25
|
!!id
|
30
26
|
end
|
31
27
|
|
32
28
|
# Sets the primary key column's value. If the primary key is composite,
|
33
29
|
# raises TypeError when the set value not enumerable.
|
34
30
|
def id=(value)
|
35
|
-
|
36
|
-
raise TypeError, "Expected value matching #{self.class.primary_key.inspect}, got #{value.inspect}." unless value.is_a?(Enumerable)
|
37
|
-
@primary_key.zip(value) { |attr, value| _write_attribute(attr, value) }
|
38
|
-
else
|
39
|
-
_write_attribute(@primary_key, value)
|
40
|
-
end
|
31
|
+
_write_attribute(@primary_key, value)
|
41
32
|
end
|
42
33
|
|
43
34
|
# Queries the primary key column's value. If the primary key is composite,
|
44
35
|
# all primary key column values must be queryable.
|
45
36
|
def id?
|
46
|
-
|
47
|
-
@primary_key.all? { |col| _query_attribute(col) }
|
48
|
-
else
|
49
|
-
_query_attribute(@primary_key)
|
50
|
-
end
|
37
|
+
_query_attribute(@primary_key)
|
51
38
|
end
|
52
39
|
|
53
40
|
# Returns the primary key column's value before type cast. If the primary key is composite,
|
54
41
|
# returns an array of primary key column values before type cast.
|
55
42
|
def id_before_type_cast
|
56
|
-
|
57
|
-
@primary_key.map { |col| attribute_before_type_cast(col) }
|
58
|
-
else
|
59
|
-
attribute_before_type_cast(@primary_key)
|
60
|
-
end
|
43
|
+
attribute_before_type_cast(@primary_key)
|
61
44
|
end
|
62
45
|
|
63
46
|
# Returns the primary key column's previous value. If the primary key is composite,
|
64
47
|
# returns an array of primary key column previous values.
|
65
48
|
def id_was
|
66
|
-
|
67
|
-
@primary_key.map { |col| attribute_was(col) }
|
68
|
-
else
|
69
|
-
attribute_was(@primary_key)
|
70
|
-
end
|
49
|
+
attribute_was(@primary_key)
|
71
50
|
end
|
72
51
|
|
73
52
|
# Returns the primary key column's value from the database. If the primary key is composite,
|
74
53
|
# returns an array of primary key column values from database.
|
75
54
|
def id_in_database
|
76
|
-
|
77
|
-
@primary_key.map { |col| attribute_in_database(col) }
|
78
|
-
else
|
79
|
-
attribute_in_database(@primary_key)
|
80
|
-
end
|
55
|
+
attribute_in_database(@primary_key)
|
81
56
|
end
|
82
57
|
|
83
58
|
def id_for_database # :nodoc:
|
84
|
-
|
85
|
-
@primary_key.map { |col| @attributes[col].value_for_database }
|
86
|
-
else
|
87
|
-
@attributes[@primary_key].value_for_database
|
88
|
-
end
|
59
|
+
@attributes[@primary_key].value_for_database
|
89
60
|
end
|
90
61
|
|
91
62
|
private
|
@@ -109,20 +80,19 @@ module ActiveRecord
|
|
109
80
|
# Overwriting will negate any effect of the +primary_key_prefix_type+
|
110
81
|
# setting, though.
|
111
82
|
def primary_key
|
112
|
-
if PRIMARY_KEY_NOT_SET.equal?(@primary_key)
|
113
|
-
@primary_key = reset_primary_key
|
114
|
-
end
|
83
|
+
reset_primary_key if PRIMARY_KEY_NOT_SET.equal?(@primary_key)
|
115
84
|
@primary_key
|
116
85
|
end
|
117
86
|
|
118
87
|
def composite_primary_key? # :nodoc:
|
119
|
-
|
88
|
+
reset_primary_key if PRIMARY_KEY_NOT_SET.equal?(@primary_key)
|
89
|
+
@composite_primary_key
|
120
90
|
end
|
121
91
|
|
122
92
|
# Returns a quoted version of the primary key name, used to construct
|
123
93
|
# SQL statements.
|
124
94
|
def quoted_primary_key
|
125
|
-
@quoted_primary_key ||=
|
95
|
+
@quoted_primary_key ||= adapter_class.quote_column_name(primary_key)
|
126
96
|
end
|
127
97
|
|
128
98
|
def reset_primary_key # :nodoc:
|
@@ -138,12 +108,10 @@ module ActiveRecord
|
|
138
108
|
base_name.foreign_key(false)
|
139
109
|
elsif base_name && primary_key_prefix_type == :table_name_with_underscore
|
140
110
|
base_name.foreign_key
|
111
|
+
elsif ActiveRecord::Base != self && table_exists?
|
112
|
+
schema_cache.primary_keys(table_name)
|
141
113
|
else
|
142
|
-
|
143
|
-
connection.schema_cache.primary_keys(table_name)
|
144
|
-
else
|
145
|
-
"id"
|
146
|
-
end
|
114
|
+
"id"
|
147
115
|
end
|
148
116
|
end
|
149
117
|
|
@@ -163,25 +131,25 @@ module ActiveRecord
|
|
163
131
|
#
|
164
132
|
# Project.primary_key # => "foo_id"
|
165
133
|
def primary_key=(value)
|
166
|
-
@primary_key
|
134
|
+
@primary_key = if value.is_a?(Array)
|
135
|
+
@composite_primary_key = true
|
136
|
+
include CompositePrimaryKey
|
137
|
+
@primary_key = value.map { |v| -v.to_s }.freeze
|
138
|
+
elsif value
|
139
|
+
-value.to_s
|
140
|
+
end
|
167
141
|
@quoted_primary_key = nil
|
168
142
|
@attributes_builder = nil
|
169
143
|
end
|
170
144
|
|
171
145
|
private
|
172
|
-
def derive_primary_key(value)
|
173
|
-
return unless value
|
174
|
-
|
175
|
-
return -value.to_s unless value.is_a?(Array)
|
176
|
-
|
177
|
-
value.map { |v| -v.to_s }.freeze
|
178
|
-
end
|
179
|
-
|
180
146
|
def inherited(base)
|
181
147
|
super
|
182
148
|
base.class_eval do
|
183
149
|
@primary_key = PRIMARY_KEY_NOT_SET
|
150
|
+
@composite_primary_key = false
|
184
151
|
@quoted_primary_key = nil
|
152
|
+
@attributes_builder = nil
|
185
153
|
end
|
186
154
|
end
|
187
155
|
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(name, owner:)
|
12
12
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
13
|
-
owner,
|
13
|
+
owner, name
|
14
14
|
) do |temp_method_name, attr_name_expr|
|
15
|
-
owner.define_cached_method(
|
15
|
+
owner.define_cached_method(name, as: temp_method_name, 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) }" <<
|
@@ -30,19 +30,7 @@ module ActiveRecord
|
|
30
30
|
name = attr_name.to_s
|
31
31
|
name = self.class.attribute_aliases[name] || name
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
if self.class.composite_primary_key?
|
36
|
-
@attributes.fetch_value("id", &block)
|
37
|
-
else
|
38
|
-
if @primary_key != "id"
|
39
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
40
|
-
Using read_attribute(:id) to read the primary key value is deprecated.
|
41
|
-
Use #id instead.
|
42
|
-
MSG
|
43
|
-
end
|
44
|
-
@attributes.fetch_value(@primary_key, &block)
|
45
|
-
end
|
33
|
+
@attributes.fetch_value(name, &block)
|
46
34
|
end
|
47
35
|
|
48
36
|
# This method exists to avoid the expensive primary_key check internally, without
|
@@ -180,29 +180,7 @@ module ActiveRecord
|
|
180
180
|
# serialize :preferences, coder: Rot13JSON
|
181
181
|
# end
|
182
182
|
#
|
183
|
-
def serialize(attr_name,
|
184
|
-
unless class_name_or_coder.nil?
|
185
|
-
if class_name_or_coder == ::JSON || [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
|
186
|
-
ActiveRecord.deprecator.warn(<<~MSG)
|
187
|
-
Passing the coder as positional argument is deprecated and will be removed in Rails 7.2.
|
188
|
-
|
189
|
-
Please pass the coder as a keyword argument:
|
190
|
-
|
191
|
-
serialize #{attr_name.inspect}, coder: #{class_name_or_coder}
|
192
|
-
MSG
|
193
|
-
coder = class_name_or_coder
|
194
|
-
else
|
195
|
-
ActiveRecord.deprecator.warn(<<~MSG)
|
196
|
-
Passing the class as positional argument is deprecated and will be removed in Rails 7.2.
|
197
|
-
|
198
|
-
Please pass the class as a keyword argument:
|
199
|
-
|
200
|
-
serialize #{attr_name.inspect}, type: #{class_name_or_coder.name}
|
201
|
-
MSG
|
202
|
-
type = class_name_or_coder
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
183
|
+
def serialize(attr_name, coder: nil, type: Object, yaml: {}, **options)
|
206
184
|
coder ||= default_column_serializer
|
207
185
|
unless coder
|
208
186
|
raise ArgumentError, <<~MSG.squish
|
@@ -214,7 +192,9 @@ module ActiveRecord
|
|
214
192
|
|
215
193
|
column_serializer = build_column_serializer(attr_name, coder, type, yaml)
|
216
194
|
|
217
|
-
attribute(attr_name, **options)
|
195
|
+
attribute(attr_name, **options)
|
196
|
+
|
197
|
+
decorate_attributes([attr_name]) do |attr_name, cast_type|
|
218
198
|
if type_incompatible_with_serialize?(cast_type, coder, type)
|
219
199
|
raise ColumnNotSerializableError.new(attr_name, cast_type)
|
220
200
|
end
|
@@ -32,10 +32,6 @@ module ActiveRecord
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def ==(other)
|
36
|
-
other.is_a?(self.class) && __getobj__ == other.__getobj__
|
37
|
-
end
|
38
|
-
|
39
35
|
private
|
40
36
|
def convert_time_to_time_zone(value)
|
41
37
|
return if value.nil?
|
@@ -73,14 +69,15 @@ module ActiveRecord
|
|
73
69
|
end
|
74
70
|
|
75
71
|
module ClassMethods # :nodoc:
|
76
|
-
|
77
|
-
|
78
|
-
|
72
|
+
private
|
73
|
+
def hook_attribute_type(name, cast_type)
|
74
|
+
if create_time_zone_conversion_attribute?(name, cast_type)
|
75
|
+
cast_type = TimeZoneConverter.new(cast_type)
|
76
|
+
end
|
77
|
+
|
78
|
+
super
|
79
79
|
end
|
80
|
-
super
|
81
|
-
end
|
82
80
|
|
83
|
-
private
|
84
81
|
def create_time_zone_conversion_attribute?(name, cast_type)
|
85
82
|
enabled_for_column = time_zone_aware_attributes &&
|
86
83
|
!skip_time_zone_conversion_for_attributes.include?(name.to_sym)
|
@@ -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=(name, owner:)
|
16
16
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
17
|
-
owner,
|
17
|
+
owner, name, writer: true,
|
18
18
|
) do |temp_method_name, attr_name_expr|
|
19
|
-
owner.define_cached_method(
|
19
|
+
owner.define_cached_method("#{name}=", as: temp_method_name, namespace: :active_record) do |batch|
|
20
20
|
batch <<
|
21
21
|
"def #{temp_method_name}(value)" <<
|
22
22
|
" _write_attribute(#{attr_name_expr}, value)" <<
|