activerecord 7.0.8.1 → 7.2.2.1
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 +642 -1925
- data/MIT-LICENSE +1 -1
- data/README.rdoc +29 -29
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +23 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- 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/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +26 -14
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- 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/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -33
- data/lib/active_record/attributes.rb +64 -50
- data/lib/active_record/autosave_association.rb +69 -37
- data/lib/active_record/base.rb +9 -5
- data/lib/active_record/callbacks.rb +11 -25
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +323 -88
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +217 -63
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +307 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +278 -125
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +370 -63
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +367 -201
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +124 -1
- data/lib/active_record/connection_handling.rb +96 -104
- data/lib/active_record/core.rb +251 -176
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +39 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +45 -21
- data/lib/active_record/encryption/encrypted_attribute_type.rb +47 -12
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +129 -28
- data/lib/active_record/errors.rb +151 -31
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +234 -117
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +92 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +33 -8
- data/lib/active_record/railtie.rb +129 -85
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +145 -154
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +250 -93
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +93 -18
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +28 -16
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +576 -107
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +580 -90
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +63 -14
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +27 -6
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +106 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- 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/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +112 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +59 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Active Record -- Object-relational mapping in Rails
|
1
|
+
= Active Record -- Object-relational mapping in \Rails
|
2
2
|
|
3
3
|
Active Record connects classes to relational database tables to establish an
|
4
4
|
almost zero-configuration persistence layer for applications. The library
|
@@ -13,29 +13,28 @@ columns. Although these mappings can be defined explicitly, it's recommended
|
|
13
13
|
to follow naming conventions, especially when getting started with the
|
14
14
|
library.
|
15
15
|
|
16
|
-
You can read more about Active Record in the {Active Record Basics}[https://
|
16
|
+
You can read more about Active Record in the {Active Record Basics}[https://guides.rubyonrails.org/active_record_basics.html] guide.
|
17
17
|
|
18
18
|
A short rundown of some of the major features:
|
19
19
|
|
20
20
|
* Automated mapping between classes and tables, attributes and columns.
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
{Learn more}[link:classes/ActiveRecord/Base.html]
|
22
|
+
class Product < ActiveRecord::Base
|
23
|
+
end
|
26
24
|
|
27
|
-
The Product class is automatically mapped to the table named "products",
|
28
|
-
which might look like this:
|
25
|
+
The Product class is automatically mapped to the table named "products",
|
26
|
+
which might look like this:
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
CREATE TABLE products (
|
29
|
+
id bigint NOT NULL auto_increment,
|
30
|
+
name varchar(255),
|
31
|
+
PRIMARY KEY (id)
|
32
|
+
);
|
35
33
|
|
36
|
-
This would also define the following accessors: <tt>Product#name</tt> and
|
37
|
-
<tt>Product#name=(new_name)</tt>.
|
34
|
+
This would also define the following accessors: <tt>Product#name</tt> and
|
35
|
+
<tt>Product#name=(new_name)</tt>.
|
38
36
|
|
37
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Base.html]
|
39
38
|
|
40
39
|
* Associations between objects defined by simple class methods.
|
41
40
|
|
@@ -45,7 +44,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
45
44
|
belongs_to :conglomerate
|
46
45
|
end
|
47
46
|
|
48
|
-
{Learn more}[
|
47
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html]
|
49
48
|
|
50
49
|
|
51
50
|
* Aggregations of value objects.
|
@@ -57,7 +56,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
57
56
|
mapping: [%w(address_street street), %w(address_city city)]
|
58
57
|
end
|
59
58
|
|
60
|
-
{Learn more}[
|
59
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Aggregations/ClassMethods.html]
|
61
60
|
|
62
61
|
|
63
62
|
* Validation rules that can differ for new or existing objects.
|
@@ -69,7 +68,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
69
68
|
validates :password, :email_address, confirmation: true, on: :create
|
70
69
|
end
|
71
70
|
|
72
|
-
{Learn more}[
|
71
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Validations.html]
|
73
72
|
|
74
73
|
|
75
74
|
* Callbacks available for the entire life cycle (instantiation, saving, destroying, validating, etc.).
|
@@ -79,7 +78,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
79
78
|
# the `invalidate_payment_plan` method gets called just before Person#destroy
|
80
79
|
end
|
81
80
|
|
82
|
-
{Learn more}[
|
81
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html]
|
83
82
|
|
84
83
|
|
85
84
|
* Inheritance hierarchies.
|
@@ -89,7 +88,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
89
88
|
class Client < Company; end
|
90
89
|
class PriorityClient < Client; end
|
91
90
|
|
92
|
-
{Learn more}[
|
91
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Base.html]
|
93
92
|
|
94
93
|
|
95
94
|
* Transactions.
|
@@ -100,7 +99,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
100
99
|
mary.deposit(100)
|
101
100
|
end
|
102
101
|
|
103
|
-
{Learn more}[
|
102
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html]
|
104
103
|
|
105
104
|
|
106
105
|
* Reflections on columns, associations, and aggregations.
|
@@ -109,7 +108,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
109
108
|
reflection.klass # => Client (class)
|
110
109
|
Firm.columns # Returns an array of column descriptors for the firms table
|
111
110
|
|
112
|
-
{Learn more}[
|
111
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html]
|
113
112
|
|
114
113
|
|
115
114
|
* Database abstraction through simple adapters.
|
@@ -126,13 +125,13 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
126
125
|
database: 'activerecord'
|
127
126
|
)
|
128
127
|
|
129
|
-
{Learn more}[
|
130
|
-
MySQL[
|
131
|
-
PostgreSQL[
|
132
|
-
SQLite3[
|
128
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Base.html] and read about the built-in support for
|
129
|
+
MySQL[https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html],
|
130
|
+
PostgreSQL[https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html], and
|
131
|
+
SQLite3[https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SQLite3Adapter.html].
|
133
132
|
|
134
133
|
|
135
|
-
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[https://ruby-
|
134
|
+
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[https://docs.ruby-lang.org/en/master/Logger.html].
|
136
135
|
|
137
136
|
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
138
137
|
ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
|
@@ -140,7 +139,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
140
139
|
|
141
140
|
* Database agnostic schema management with Migrations.
|
142
141
|
|
143
|
-
class AddSystemSettings < ActiveRecord::Migration[7.
|
142
|
+
class AddSystemSettings < ActiveRecord::Migration[7.2]
|
144
143
|
def up
|
145
144
|
create_table :system_settings do |t|
|
146
145
|
t.string :name
|
@@ -158,7 +157,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
158
157
|
end
|
159
158
|
end
|
160
159
|
|
161
|
-
{Learn more}[
|
160
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Migration.html]
|
162
161
|
|
163
162
|
|
164
163
|
== Philosophy
|
@@ -167,6 +166,7 @@ Active Record is an implementation of the object-relational mapping (ORM)
|
|
167
166
|
pattern[https://www.martinfowler.com/eaaCatalog/activeRecord.html] by the same
|
168
167
|
name described by Martin Fowler:
|
169
168
|
|
169
|
+
>>>
|
170
170
|
"An object that wraps a row in a database table or view,
|
171
171
|
encapsulates the database access, and adds domain logic on that data."
|
172
172
|
|
data/examples/performance.rb
CHANGED
@@ -176,10 +176,10 @@ Benchmark.ips(TIME) do |x|
|
|
176
176
|
end
|
177
177
|
|
178
178
|
x.report "Model.log" do
|
179
|
-
Exhibit.
|
179
|
+
Exhibit.lease_connection.send(:log, "hello", "world") { }
|
180
180
|
end
|
181
181
|
|
182
182
|
x.report "AR.execute(query)" do
|
183
|
-
ActiveRecord::Base.
|
183
|
+
ActiveRecord::Base.lease_connection.execute("SELECT * FROM exhibits WHERE id = #{(rand * 1000 + 1).to_i}")
|
184
184
|
end
|
185
185
|
end
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
# See ActiveRecord::Aggregations::ClassMethods for documentation
|
5
5
|
module Aggregations
|
6
6
|
def initialize_dup(*) # :nodoc:
|
7
|
-
@aggregation_cache =
|
7
|
+
@aggregation_cache = @aggregation_cache.dup
|
8
8
|
super
|
9
9
|
end
|
10
10
|
|
@@ -19,10 +19,12 @@ module ActiveRecord
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def init_internals
|
22
|
-
@aggregation_cache = {}
|
23
22
|
super
|
23
|
+
@aggregation_cache = {}
|
24
24
|
end
|
25
25
|
|
26
|
+
# = Active Record \Aggregations
|
27
|
+
#
|
26
28
|
# Active Record implements aggregation through a macro-like class method called #composed_of
|
27
29
|
# for representing attributes as value objects. It expresses relationships like "Account [is]
|
28
30
|
# composed of Money [among other things]" or "Person [is] composed of [an] address". Each call
|
@@ -32,8 +34,8 @@ module ActiveRecord
|
|
32
34
|
# the database).
|
33
35
|
#
|
34
36
|
# class Customer < ActiveRecord::Base
|
35
|
-
# composed_of :balance, class_name: "Money", mapping:
|
36
|
-
# composed_of :address, mapping:
|
37
|
+
# composed_of :balance, class_name: "Money", mapping: { balance: :amount }
|
38
|
+
# composed_of :address, mapping: { address_street: :street, address_city: :city }
|
37
39
|
# end
|
38
40
|
#
|
39
41
|
# The customer class now has the following methods to manipulate the value objects:
|
@@ -150,7 +152,7 @@ module ActiveRecord
|
|
150
152
|
# class NetworkResource < ActiveRecord::Base
|
151
153
|
# composed_of :cidr,
|
152
154
|
# class_name: 'NetAddr::CIDR',
|
153
|
-
# mapping:
|
155
|
+
# mapping: { network_address: :network, cidr_range: :bits },
|
154
156
|
# allow_nil: true,
|
155
157
|
# constructor: Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
|
156
158
|
# converter: Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
|
@@ -188,10 +190,10 @@ module ActiveRecord
|
|
188
190
|
# to the Address class, but if the real class name is +CompanyAddress+, you'll have to specify it
|
189
191
|
# with this option.
|
190
192
|
# * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value
|
191
|
-
# object. Each mapping is represented as
|
192
|
-
# entity attribute and the
|
193
|
+
# object. Each mapping is represented as a key-value pair where the key is the name of the
|
194
|
+
# entity attribute and the value is the name of the attribute in the value object. The
|
193
195
|
# order in which mappings are defined determines the order in which attributes are sent to the
|
194
|
-
# value class constructor.
|
196
|
+
# value class constructor. The mapping can be written as a hash or as an array of pairs.
|
195
197
|
# * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped
|
196
198
|
# attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all
|
197
199
|
# mapped attributes.
|
@@ -208,14 +210,15 @@ module ActiveRecord
|
|
208
210
|
# can return +nil+ to skip the assignment.
|
209
211
|
#
|
210
212
|
# Option examples:
|
211
|
-
# composed_of :temperature, mapping:
|
212
|
-
# composed_of :balance, class_name: "Money", mapping:
|
213
|
+
# composed_of :temperature, mapping: { reading: :celsius }
|
214
|
+
# composed_of :balance, class_name: "Money", mapping: { balance: :amount }
|
215
|
+
# composed_of :address, mapping: { address_street: :street, address_city: :city }
|
213
216
|
# composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
|
214
217
|
# composed_of :gps_location
|
215
218
|
# composed_of :gps_location, allow_nil: true
|
216
219
|
# composed_of :ip_address,
|
217
220
|
# class_name: 'IPAddr',
|
218
|
-
# mapping:
|
221
|
+
# mapping: { ip: :to_i },
|
219
222
|
# constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
|
220
223
|
# converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
|
221
224
|
#
|
@@ -249,7 +252,7 @@ module ActiveRecord
|
|
249
252
|
object = constructor.respond_to?(:call) ?
|
250
253
|
constructor.call(*attrs) :
|
251
254
|
class_name.constantize.send(constructor, *attrs)
|
252
|
-
@aggregation_cache[name] = object
|
255
|
+
@aggregation_cache[name] = object.freeze
|
253
256
|
end
|
254
257
|
@aggregation_cache[name]
|
255
258
|
end
|
@@ -275,7 +278,7 @@ module ActiveRecord
|
|
275
278
|
@aggregation_cache[name] = nil
|
276
279
|
else
|
277
280
|
mapping.each { |key, value| write_attribute(key, part.send(value)) }
|
278
|
-
@aggregation_cache[name] = part.freeze
|
281
|
+
@aggregation_cache[name] = part.dup.freeze
|
279
282
|
end
|
280
283
|
end
|
281
284
|
end
|
@@ -16,13 +16,13 @@ module ActiveRecord
|
|
16
16
|
end
|
17
17
|
|
18
18
|
%w(insert insert_all insert! insert_all! upsert upsert_all).each do |method|
|
19
|
-
class_eval <<~RUBY
|
19
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
20
20
|
def #{method}(attributes, **kwargs)
|
21
21
|
if @association.reflection.through_reflection?
|
22
22
|
raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
super
|
26
26
|
end
|
27
27
|
RUBY
|
28
28
|
end
|
@@ -6,21 +6,23 @@ module ActiveRecord
|
|
6
6
|
module Associations
|
7
7
|
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
|
8
8
|
class AliasTracker # :nodoc:
|
9
|
-
def self.create(
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
def self.create(pool, initial_table, joins, aliases = nil)
|
10
|
+
pool.with_connection do |connection|
|
11
|
+
if joins.empty?
|
12
|
+
aliases ||= Hash.new(0)
|
13
|
+
elsif aliases
|
14
|
+
default_proc = aliases.default_proc || proc { 0 }
|
15
|
+
aliases.default_proc = proc { |h, k|
|
16
|
+
h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
|
17
|
+
}
|
18
|
+
else
|
19
|
+
aliases = Hash.new { |h, k|
|
20
|
+
h[k] = initial_count_for(connection, k, joins)
|
21
|
+
}
|
22
|
+
end
|
23
|
+
aliases[initial_table] = 1
|
24
|
+
new(connection.table_alias_length, aliases)
|
21
25
|
end
|
22
|
-
aliases[initial_table] = 1
|
23
|
-
new(connection, aliases)
|
24
26
|
end
|
25
27
|
|
26
28
|
def self.initial_count_for(connection, name, table_joins)
|
@@ -46,9 +48,9 @@ module ActiveRecord
|
|
46
48
|
end
|
47
49
|
|
48
50
|
# table_joins is an array of arel joins which might conflict with the aliases we assign here
|
49
|
-
def initialize(
|
50
|
-
@aliases
|
51
|
-
@
|
51
|
+
def initialize(table_alias_length, aliases)
|
52
|
+
@aliases = aliases
|
53
|
+
@table_alias_length = table_alias_length
|
52
54
|
end
|
53
55
|
|
54
56
|
def aliased_table_for(arel_table, table_name = nil)
|
@@ -60,7 +62,7 @@ module ActiveRecord
|
|
60
62
|
arel_table = arel_table.alias(table_name) if arel_table.name != table_name
|
61
63
|
else
|
62
64
|
# Otherwise, we need to use an alias
|
63
|
-
aliased_name =
|
65
|
+
aliased_name = table_alias_for(yield)
|
64
66
|
|
65
67
|
# Update the count
|
66
68
|
count = aliases[aliased_name] += 1
|
@@ -76,8 +78,12 @@ module ActiveRecord
|
|
76
78
|
attr_reader :aliases
|
77
79
|
|
78
80
|
private
|
81
|
+
def table_alias_for(table_name)
|
82
|
+
table_name[0...@table_alias_length].tr(".", "_")
|
83
|
+
end
|
84
|
+
|
79
85
|
def truncate(name)
|
80
|
-
name.slice(0, @
|
86
|
+
name.slice(0, @table_alias_length - 2)
|
81
87
|
end
|
82
88
|
end
|
83
89
|
end
|
@@ -19,7 +19,7 @@ module ActiveRecord
|
|
19
19
|
# Associations in Active Record are middlemen between the object that
|
20
20
|
# holds the association, known as the <tt>owner</tt>, and the associated
|
21
21
|
# result set, known as the <tt>target</tt>. Association metadata is available in
|
22
|
-
# <tt>reflection</tt>, which is an instance of
|
22
|
+
# <tt>reflection</tt>, which is an instance of +ActiveRecord::Reflection::AssociationReflection+.
|
23
23
|
#
|
24
24
|
# For example, given
|
25
25
|
#
|
@@ -33,7 +33,8 @@ module ActiveRecord
|
|
33
33
|
# <tt>owner</tt>, the collection of its posts as <tt>target</tt>, and
|
34
34
|
# the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
|
35
35
|
class Association # :nodoc:
|
36
|
-
|
36
|
+
attr_accessor :owner
|
37
|
+
attr_reader :target, :reflection, :disable_joins
|
37
38
|
|
38
39
|
delegate :options, to: :reflection
|
39
40
|
|
@@ -45,12 +46,13 @@ module ActiveRecord
|
|
45
46
|
|
46
47
|
reset
|
47
48
|
reset_scope
|
49
|
+
|
50
|
+
@skip_strict_loading = nil
|
48
51
|
end
|
49
52
|
|
50
53
|
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
|
51
54
|
def reset
|
52
55
|
@loaded = false
|
53
|
-
@target = nil
|
54
56
|
@stale_state = nil
|
55
57
|
end
|
56
58
|
|
@@ -61,7 +63,7 @@ module ActiveRecord
|
|
61
63
|
# Reloads the \target and returns +self+ on success.
|
62
64
|
# The QueryCache is cleared if +force+ is true.
|
63
65
|
def reload(force = false)
|
64
|
-
klass.
|
66
|
+
klass.connection_pool.clear_query_cache if force && klass
|
65
67
|
reset
|
66
68
|
reset_scope
|
67
69
|
load_target
|
@@ -208,6 +210,12 @@ module ActiveRecord
|
|
208
210
|
_create_record(attributes, true, &block)
|
209
211
|
end
|
210
212
|
|
213
|
+
# Whether the association represent a single record
|
214
|
+
# or a collection of records.
|
215
|
+
def collection?
|
216
|
+
false
|
217
|
+
end
|
218
|
+
|
211
219
|
private
|
212
220
|
# Reader and writer methods call this so that consistent errors are presented
|
213
221
|
# when the association target class does not exist.
|
@@ -216,7 +224,7 @@ module ActiveRecord
|
|
216
224
|
end
|
217
225
|
|
218
226
|
def find_target
|
219
|
-
if violates_strict_loading?
|
227
|
+
if violates_strict_loading?
|
220
228
|
Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
|
221
229
|
end
|
222
230
|
|
@@ -229,17 +237,31 @@ module ActiveRecord
|
|
229
237
|
end
|
230
238
|
|
231
239
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
240
|
+
klass.with_connection do |c|
|
241
|
+
sc.execute(binds, c) do |record|
|
242
|
+
set_inverse_instance(record)
|
243
|
+
if owner.strict_loading_n_plus_one_only? && reflection.macro == :has_many
|
244
|
+
record.strict_loading!
|
245
|
+
else
|
246
|
+
record.strict_loading!(false, mode: owner.strict_loading_mode)
|
247
|
+
end
|
238
248
|
end
|
239
249
|
end
|
240
250
|
end
|
241
251
|
|
252
|
+
def skip_strict_loading(&block)
|
253
|
+
skip_strict_loading_was = @skip_strict_loading
|
254
|
+
@skip_strict_loading = true
|
255
|
+
yield
|
256
|
+
ensure
|
257
|
+
@skip_strict_loading = skip_strict_loading_was
|
258
|
+
end
|
259
|
+
|
242
260
|
def violates_strict_loading?
|
261
|
+
return if @skip_strict_loading
|
262
|
+
|
263
|
+
return unless owner.validation_context.nil?
|
264
|
+
|
243
265
|
return reflection.strict_loading? if reflection.options.key?(:strict_loading)
|
244
266
|
|
245
267
|
owner.strict_loading? && !owner.strict_loading_n_plus_one_only?
|
@@ -322,7 +344,8 @@ module ActiveRecord
|
|
322
344
|
|
323
345
|
# Returns true if record contains the foreign_key
|
324
346
|
def foreign_key_for?(record)
|
325
|
-
|
347
|
+
foreign_key = Array(reflection.foreign_key)
|
348
|
+
foreign_key.all? { |key| record._has_attribute?(key) }
|
326
349
|
end
|
327
350
|
|
328
351
|
# This should be implemented to return the values of the relevant key(s) on the owner,
|
@@ -35,7 +35,7 @@ module ActiveRecord
|
|
35
35
|
binds = []
|
36
36
|
last_reflection = chain.last
|
37
37
|
|
38
|
-
binds
|
38
|
+
binds.push(*last_reflection.join_id_for(owner))
|
39
39
|
if last_reflection.type
|
40
40
|
binds << owner.class.polymorphic_name
|
41
41
|
end
|
@@ -56,12 +56,15 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def last_chain_scope(scope, reflection, owner)
|
59
|
-
primary_key = reflection.join_primary_key
|
60
|
-
foreign_key = reflection.join_foreign_key
|
59
|
+
primary_key = Array(reflection.join_primary_key)
|
60
|
+
foreign_key = Array(reflection.join_foreign_key)
|
61
61
|
|
62
62
|
table = reflection.aliased_table
|
63
|
-
|
64
|
-
|
63
|
+
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
64
|
+
primary_key_foreign_key_pairs.each do |join_key, foreign_key|
|
65
|
+
value = transform_value(owner._read_attribute(foreign_key))
|
66
|
+
scope = apply_scope(scope, table, join_key, value)
|
67
|
+
end
|
65
68
|
|
66
69
|
if reflection.type
|
67
70
|
polymorphic_type = transform_value(owner.class.polymorphic_name)
|
@@ -76,19 +79,23 @@ module ActiveRecord
|
|
76
79
|
end
|
77
80
|
|
78
81
|
def next_chain_scope(scope, reflection, next_reflection)
|
79
|
-
primary_key = reflection.join_primary_key
|
80
|
-
foreign_key = reflection.join_foreign_key
|
82
|
+
primary_key = Array(reflection.join_primary_key)
|
83
|
+
foreign_key = Array(reflection.join_foreign_key)
|
81
84
|
|
82
85
|
table = reflection.aliased_table
|
83
86
|
foreign_table = next_reflection.aliased_table
|
84
|
-
|
87
|
+
|
88
|
+
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
89
|
+
constraints = primary_key_foreign_key_pairs.map do |join_primary_key, foreign_key|
|
90
|
+
table[join_primary_key].eq(foreign_table[foreign_key])
|
91
|
+
end.inject(&:and)
|
85
92
|
|
86
93
|
if reflection.type
|
87
94
|
value = transform_value(next_reflection.klass.polymorphic_name)
|
88
95
|
scope = apply_scope(scope, table, reflection.type, value)
|
89
96
|
end
|
90
97
|
|
91
|
-
scope.joins!(join(foreign_table,
|
98
|
+
scope.joins!(join(foreign_table, constraints))
|
92
99
|
end
|
93
100
|
|
94
101
|
class ReflectionProxy < SimpleDelegator # :nodoc:
|
@@ -11,8 +11,13 @@ module ActiveRecord
|
|
11
11
|
when :destroy
|
12
12
|
raise ActiveRecord::Rollback unless target.destroy
|
13
13
|
when :destroy_async
|
14
|
-
|
15
|
-
|
14
|
+
if reflection.foreign_key.is_a?(Array)
|
15
|
+
primary_key_column = reflection.active_record_primary_key
|
16
|
+
id = reflection.foreign_key.map { |col| owner.public_send(col) }
|
17
|
+
else
|
18
|
+
primary_key_column = reflection.active_record_primary_key
|
19
|
+
id = owner.public_send(reflection.foreign_key)
|
20
|
+
end
|
16
21
|
|
17
22
|
enqueue_destroy_association(
|
18
23
|
owner_model_name: owner.class.to_s,
|
@@ -119,10 +124,21 @@ module ActiveRecord
|
|
119
124
|
end
|
120
125
|
|
121
126
|
def replace_keys(record, force: false)
|
122
|
-
|
127
|
+
reflection_fk = reflection.foreign_key
|
128
|
+
if reflection_fk.is_a?(Array)
|
129
|
+
target_key_values = record ? Array(primary_key(record.class)).map { |key| record._read_attribute(key) } : []
|
130
|
+
|
131
|
+
if force || reflection_fk.map { |fk| owner._read_attribute(fk) } != target_key_values
|
132
|
+
reflection_fk.each_with_index do |key, index|
|
133
|
+
owner[key] = target_key_values[index]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
else
|
137
|
+
target_key_value = record ? record._read_attribute(primary_key(record.class)) : nil
|
123
138
|
|
124
|
-
|
125
|
-
|
139
|
+
if force || owner._read_attribute(reflection_fk) != target_key_value
|
140
|
+
owner[reflection_fk] = target_key_value
|
141
|
+
end
|
126
142
|
end
|
127
143
|
end
|
128
144
|
|
@@ -131,7 +147,7 @@ module ActiveRecord
|
|
131
147
|
end
|
132
148
|
|
133
149
|
def foreign_key_present?
|
134
|
-
|
150
|
+
Array(reflection.foreign_key).all? { |fk| owner._read_attribute(fk) }
|
135
151
|
end
|
136
152
|
|
137
153
|
def invertible_for?(record)
|
@@ -140,8 +156,7 @@ module ActiveRecord
|
|
140
156
|
end
|
141
157
|
|
142
158
|
def stale_state
|
143
|
-
|
144
|
-
result && result.to_s
|
159
|
+
owner._read_attribute(reflection.foreign_key) { |n| owner.send(:missing_attribute, n, caller) }
|
145
160
|
end
|
146
161
|
end
|
147
162
|
end
|
@@ -19,7 +19,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
19
19
|
self.extensions = []
|
20
20
|
|
21
21
|
VALID_OPTIONS = [
|
22
|
-
:class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading
|
22
|
+
:class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading, :query_constraints
|
23
23
|
].freeze # :nodoc:
|
24
24
|
|
25
25
|
def self.build(model, name, scope, options, &block)
|
@@ -128,8 +128,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
128
128
|
|
129
129
|
def self.check_dependent_options(dependent, model)
|
130
130
|
if dependent == :destroy_async && !model.destroy_association_async_job
|
131
|
-
err_message = "
|
132
|
-
raise ActiveRecord::
|
131
|
+
err_message = "A valid destroy_association_async_job is required to use `dependent: :destroy_async` on associations"
|
132
|
+
raise ActiveRecord::ConfigurationError, err_message
|
133
133
|
end
|
134
134
|
unless valid_dependent_options.include? dependent
|
135
135
|
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
|