activerecord 7.1.5 → 7.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +515 -2440
- 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)" <<
|