activerecord 6.1.7 → 7.2.2
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 +616 -1290
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- 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 +29 -19
- data/lib/active_record/associations/has_many_through_association.rb +19 -8
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +429 -522
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +15 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +57 -54
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- data/lib/active_record/callbacks.rb +19 -35
- 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 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +325 -604
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +230 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -143
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +348 -165
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- 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 +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +403 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +520 -253
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- 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 +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +310 -253
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -4
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +170 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +170 -62
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- 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 +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- 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 +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- 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/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +374 -177
- data/lib/active_record/model_schema.rb +145 -158
- data/lib/active_record/nested_attributes.rb +61 -23
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +229 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +332 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +200 -65
- data/lib/active_record/relation/calculations.rb +301 -112
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- 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 +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +870 -163
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +6 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +288 -149
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- 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 +118 -41
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- 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 +13 -7
- 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 +65 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- 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/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- 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
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +103 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "mutex_m"
|
4
3
|
require "active_support/core_ext/enumerable"
|
5
4
|
|
6
5
|
module ActiveRecord
|
@@ -21,10 +20,10 @@ module ActiveRecord
|
|
21
20
|
include Serialization
|
22
21
|
end
|
23
22
|
|
24
|
-
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name
|
23
|
+
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name superclass)
|
25
24
|
|
26
|
-
class GeneratedAttributeMethods < Module
|
27
|
-
|
25
|
+
class GeneratedAttributeMethods < Module # :nodoc:
|
26
|
+
LOCK = Monitor.new
|
28
27
|
end
|
29
28
|
|
30
29
|
class << self
|
@@ -33,44 +32,118 @@ module ActiveRecord
|
|
33
32
|
Base.instance_methods +
|
34
33
|
Base.private_instance_methods -
|
35
34
|
Base.superclass.instance_methods -
|
36
|
-
Base.superclass.private_instance_methods
|
35
|
+
Base.superclass.private_instance_methods +
|
36
|
+
%i[__id__ dup freeze frozen? hash class clone]
|
37
37
|
).map { |m| -m.to_s }.to_set.freeze
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
module ClassMethods
|
42
|
-
def inherited(child_class) #:nodoc:
|
43
|
-
child_class.initialize_generated_modules
|
44
|
-
super
|
45
|
-
end
|
46
|
-
|
47
42
|
def initialize_generated_modules # :nodoc:
|
48
43
|
@generated_attribute_methods = const_set(:GeneratedAttributeMethods, GeneratedAttributeMethods.new)
|
49
44
|
private_constant :GeneratedAttributeMethods
|
50
45
|
@attribute_methods_generated = false
|
46
|
+
@alias_attributes_mass_generated = false
|
51
47
|
include @generated_attribute_methods
|
52
48
|
|
53
49
|
super
|
54
50
|
end
|
55
51
|
|
52
|
+
# Allows you to make aliases for attributes.
|
53
|
+
#
|
54
|
+
# class Person < ActiveRecord::Base
|
55
|
+
# alias_attribute :nickname, :name
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# person = Person.create(name: 'Bob')
|
59
|
+
# person.name # => "Bob"
|
60
|
+
# person.nickname # => "Bob"
|
61
|
+
#
|
62
|
+
# The alias can also be used for querying:
|
63
|
+
#
|
64
|
+
# Person.where(nickname: "Bob")
|
65
|
+
# # SELECT "people".* FROM "people" WHERE "people"."name" = "Bob"
|
66
|
+
def alias_attribute(new_name, old_name)
|
67
|
+
super
|
68
|
+
|
69
|
+
if @alias_attributes_mass_generated
|
70
|
+
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
|
71
|
+
generate_alias_attribute_methods(code_generator, new_name, old_name)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def eagerly_generate_alias_attribute_methods(_new_name, _old_name) # :nodoc:
|
77
|
+
# alias attributes in Active Record are lazily generated
|
78
|
+
end
|
79
|
+
|
80
|
+
def generate_alias_attribute_methods(code_generator, new_name, old_name) # :nodoc:
|
81
|
+
attribute_method_patterns.each do |pattern|
|
82
|
+
alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
|
83
|
+
end
|
84
|
+
attribute_method_patterns_cache.clear
|
85
|
+
end
|
86
|
+
|
87
|
+
def alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
|
88
|
+
old_name = old_name.to_s
|
89
|
+
|
90
|
+
if !abstract_class? && !has_attribute?(old_name)
|
91
|
+
raise ArgumentError, "#{self.name} model aliases `#{old_name}`, but `#{old_name}` is not an attribute. " \
|
92
|
+
"Use `alias_method :#{new_name}, :#{old_name}` or define the method manually."
|
93
|
+
else
|
94
|
+
define_attribute_method_pattern(pattern, old_name, owner: code_generator, as: new_name, override: true)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def attribute_methods_generated? # :nodoc:
|
99
|
+
@attribute_methods_generated
|
100
|
+
end
|
101
|
+
|
56
102
|
# Generates all the attribute related methods for columns in the database
|
57
103
|
# accessors, mutators and query methods.
|
58
104
|
def define_attribute_methods # :nodoc:
|
59
105
|
return false if @attribute_methods_generated
|
60
106
|
# Use a mutex; we don't want two threads simultaneously trying to define
|
61
107
|
# attribute methods.
|
62
|
-
|
108
|
+
GeneratedAttributeMethods::LOCK.synchronize do
|
63
109
|
return false if @attribute_methods_generated
|
110
|
+
|
64
111
|
superclass.define_attribute_methods unless base_class?
|
65
|
-
|
112
|
+
|
113
|
+
unless abstract_class?
|
114
|
+
load_schema
|
115
|
+
super(attribute_names)
|
116
|
+
alias_attribute :id_value, :id if _has_attribute?("id")
|
117
|
+
end
|
118
|
+
|
66
119
|
@attribute_methods_generated = true
|
120
|
+
|
121
|
+
generate_alias_attributes
|
67
122
|
end
|
123
|
+
true
|
124
|
+
end
|
125
|
+
|
126
|
+
def generate_alias_attributes # :nodoc:
|
127
|
+
superclass.generate_alias_attributes unless superclass == Base
|
128
|
+
|
129
|
+
return if @alias_attributes_mass_generated
|
130
|
+
|
131
|
+
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
|
132
|
+
aliases_by_attribute_name.each do |old_name, new_names|
|
133
|
+
new_names.each do |new_name|
|
134
|
+
generate_alias_attribute_methods(code_generator, new_name, old_name)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
@alias_attributes_mass_generated = true
|
68
140
|
end
|
69
141
|
|
70
142
|
def undefine_attribute_methods # :nodoc:
|
71
|
-
|
72
|
-
super if
|
143
|
+
GeneratedAttributeMethods::LOCK.synchronize do
|
144
|
+
super if @attribute_methods_generated
|
73
145
|
@attribute_methods_generated = false
|
146
|
+
@alias_attributes_mass_generated = false
|
74
147
|
end
|
75
148
|
end
|
76
149
|
|
@@ -97,7 +170,7 @@ module ActiveRecord
|
|
97
170
|
super
|
98
171
|
else
|
99
172
|
# If ThisClass < ... < SomeSuperClass < ... < Base and SomeSuperClass
|
100
|
-
# defines its own attribute method, then we don't want to
|
173
|
+
# defines its own attribute method, then we don't want to override that.
|
101
174
|
defined = method_defined_within?(method_name, superclass, Base) &&
|
102
175
|
! superclass.instance_method(method_name).owner.is_a?(GeneratedAttributeMethods)
|
103
176
|
defined || super
|
@@ -186,6 +259,16 @@ module ActiveRecord
|
|
186
259
|
def _has_attribute?(attr_name) # :nodoc:
|
187
260
|
attribute_types.key?(attr_name)
|
188
261
|
end
|
262
|
+
|
263
|
+
private
|
264
|
+
def inherited(child_class)
|
265
|
+
super
|
266
|
+
child_class.initialize_generated_modules
|
267
|
+
child_class.class_eval do
|
268
|
+
@alias_attributes_mass_generated = false
|
269
|
+
@attribute_names = nil
|
270
|
+
end
|
271
|
+
end
|
189
272
|
end
|
190
273
|
|
191
274
|
# A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
|
@@ -209,9 +292,7 @@ module ActiveRecord
|
|
209
292
|
|
210
293
|
# If the result is true then check for the select case.
|
211
294
|
# For queries selecting a subset of columns, return false for unselected columns.
|
212
|
-
|
213
|
-
# have been allocated but not yet initialized.
|
214
|
-
if defined?(@attributes)
|
295
|
+
if @attributes
|
215
296
|
if name = self.class.symbol_column_to_string(name.to_sym)
|
216
297
|
return _has_attribute?(name)
|
217
298
|
end
|
@@ -267,9 +348,8 @@ module ActiveRecord
|
|
267
348
|
|
268
349
|
# Returns an <tt>#inspect</tt>-like string for the value of the
|
269
350
|
# attribute +attr_name+. String attributes are truncated up to 50
|
270
|
-
# characters
|
271
|
-
#
|
272
|
-
# <tt>#inspect</tt> without modification.
|
351
|
+
# characters. Other attributes return the value of <tt>#inspect</tt>
|
352
|
+
# without modification.
|
273
353
|
#
|
274
354
|
# person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
|
275
355
|
#
|
@@ -277,7 +357,7 @@ module ActiveRecord
|
|
277
357
|
# # => "\"David Heinemeier Hansson David Heinemeier Hansson ...\""
|
278
358
|
#
|
279
359
|
# person.attribute_for_inspect(:created_at)
|
280
|
-
# # => "\"2012-10-22 00:15:07\""
|
360
|
+
# # => "\"2012-10-22 00:15:07.000000000 +0000\""
|
281
361
|
#
|
282
362
|
# person.attribute_for_inspect(:tag_ids)
|
283
363
|
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
|
@@ -310,37 +390,40 @@ module ActiveRecord
|
|
310
390
|
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
|
311
391
|
end
|
312
392
|
|
313
|
-
# Returns the value of the attribute identified by
|
314
|
-
#
|
315
|
-
#
|
316
|
-
#
|
317
|
-
# Note: +:id+ is always present.
|
393
|
+
# Returns the value of the attribute identified by +attr_name+ after it has
|
394
|
+
# been type cast. (For information about specific type casting behavior, see
|
395
|
+
# the types under ActiveModel::Type.)
|
318
396
|
#
|
319
397
|
# class Person < ActiveRecord::Base
|
320
398
|
# belongs_to :organization
|
321
399
|
# end
|
322
400
|
#
|
323
|
-
# person = Person.new(name:
|
324
|
-
# person[:name]
|
325
|
-
# person[:
|
401
|
+
# person = Person.new(name: "Francesco", date_of_birth: "2004-12-12")
|
402
|
+
# person[:name] # => "Francesco"
|
403
|
+
# person[:date_of_birth] # => Date.new(2004, 12, 12)
|
404
|
+
# person[:organization_id] # => nil
|
405
|
+
#
|
406
|
+
# Raises ActiveModel::MissingAttributeError if the attribute is missing.
|
407
|
+
# Note, however, that the +id+ attribute will never be considered missing.
|
326
408
|
#
|
327
|
-
# person = Person.select(
|
328
|
-
# person[:name] # =>
|
329
|
-
# person[:
|
409
|
+
# person = Person.select(:name).first
|
410
|
+
# person[:name] # => "Francesco"
|
411
|
+
# person[:date_of_birth] # => ActiveModel::MissingAttributeError: missing attribute 'date_of_birth' for Person
|
412
|
+
# person[:organization_id] # => ActiveModel::MissingAttributeError: missing attribute 'organization_id' for Person
|
413
|
+
# person[:id] # => nil
|
330
414
|
def [](attr_name)
|
331
415
|
read_attribute(attr_name) { |n| missing_attribute(n, caller) }
|
332
416
|
end
|
333
417
|
|
334
|
-
# Updates the attribute identified by
|
335
|
-
#
|
418
|
+
# Updates the attribute identified by +attr_name+ using the specified
|
419
|
+
# +value+. The attribute value will be type cast upon being read.
|
336
420
|
#
|
337
421
|
# class Person < ActiveRecord::Base
|
338
422
|
# end
|
339
423
|
#
|
340
424
|
# person = Person.new
|
341
|
-
# person[:
|
342
|
-
# person[:
|
343
|
-
# person[:age].class # => Integer
|
425
|
+
# person[:date_of_birth] = "2004-12-12"
|
426
|
+
# person[:date_of_birth] # => Date.new(2004, 12, 12)
|
344
427
|
def []=(attr_name, value)
|
345
428
|
write_attribute(attr_name, value)
|
346
429
|
end
|
@@ -361,10 +444,9 @@ module ActiveRecord
|
|
361
444
|
# end
|
362
445
|
#
|
363
446
|
# private
|
364
|
-
#
|
365
|
-
#
|
366
|
-
#
|
367
|
-
# end
|
447
|
+
# def print_accessed_fields
|
448
|
+
# p @posts.first.accessed_fields
|
449
|
+
# end
|
368
450
|
# end
|
369
451
|
#
|
370
452
|
# Which allows you to quickly change your code to:
|
@@ -379,31 +461,61 @@ module ActiveRecord
|
|
379
461
|
end
|
380
462
|
|
381
463
|
private
|
464
|
+
def respond_to_missing?(name, include_private = false)
|
465
|
+
if self.class.define_attribute_methods
|
466
|
+
# Some methods weren't defined yet.
|
467
|
+
return true if self.class.method_defined?(name)
|
468
|
+
return true if include_private && self.class.private_method_defined?(name)
|
469
|
+
end
|
470
|
+
|
471
|
+
super
|
472
|
+
end
|
473
|
+
|
474
|
+
def method_missing(name, ...)
|
475
|
+
unless self.class.attribute_methods_generated?
|
476
|
+
if self.class.method_defined?(name)
|
477
|
+
# The method is explicitly defined in the model, but calls a generated
|
478
|
+
# method with super. So we must resume the call chain at the right step.
|
479
|
+
last_method = method(name)
|
480
|
+
last_method = last_method.super_method while last_method.super_method
|
481
|
+
self.class.define_attribute_methods
|
482
|
+
if last_method.super_method
|
483
|
+
return last_method.super_method.call(...)
|
484
|
+
end
|
485
|
+
elsif self.class.define_attribute_methods
|
486
|
+
# Some attribute methods weren't generated yet, we retry the call
|
487
|
+
return public_send(name, ...)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
super
|
492
|
+
end
|
493
|
+
|
382
494
|
def attribute_method?(attr_name)
|
383
|
-
|
384
|
-
defined?(@attributes) && @attributes.key?(attr_name)
|
495
|
+
@attributes&.key?(attr_name)
|
385
496
|
end
|
386
497
|
|
387
498
|
def attributes_with_values(attribute_names)
|
388
|
-
attribute_names.index_with
|
389
|
-
_read_attribute(name)
|
390
|
-
end
|
499
|
+
attribute_names.index_with { |name| @attributes[name] }
|
391
500
|
end
|
392
501
|
|
393
|
-
# Filters the primary keys
|
502
|
+
# Filters the primary keys, readonly attributes and virtual columns from the attribute names.
|
394
503
|
def attributes_for_update(attribute_names)
|
395
504
|
attribute_names &= self.class.column_names
|
396
505
|
attribute_names.delete_if do |name|
|
397
|
-
self.class.readonly_attribute?(name)
|
506
|
+
self.class.readonly_attribute?(name) ||
|
507
|
+
self.class.counter_cache_column?(name) ||
|
508
|
+
column_for_attribute(name).virtual?
|
398
509
|
end
|
399
510
|
end
|
400
511
|
|
401
|
-
# Filters out the primary keys, from the attribute names, when the primary
|
512
|
+
# Filters out the virtual columns and also primary keys, from the attribute names, when the primary
|
402
513
|
# key is to be generated (e.g. the id attribute has no value).
|
403
514
|
def attributes_for_create(attribute_names)
|
404
515
|
attribute_names &= self.class.column_names
|
405
516
|
attribute_names.delete_if do |name|
|
406
|
-
pk_attribute?(name) && id.nil?
|
517
|
+
(pk_attribute?(name) && id.nil?) ||
|
518
|
+
column_for_attribute(name).virtual?
|
407
519
|
end
|
408
520
|
end
|
409
521
|
|
@@ -414,7 +526,7 @@ module ActiveRecord
|
|
414
526
|
inspected_value = if value.is_a?(String) && value.length > 50
|
415
527
|
"#{value[0, 50]}...".inspect
|
416
528
|
elsif value.is_a?(Date) || value.is_a?(Time)
|
417
|
-
%("#{value.
|
529
|
+
%("#{value.to_fs(:inspect)}")
|
418
530
|
else
|
419
531
|
value.inspect
|
420
532
|
end
|
@@ -6,13 +6,11 @@ module ActiveRecord
|
|
6
6
|
# See ActiveRecord::Attributes::ClassMethods for documentation
|
7
7
|
module Attributes
|
8
8
|
extend ActiveSupport::Concern
|
9
|
+
include ActiveModel::AttributeRegistration
|
9
10
|
|
10
|
-
|
11
|
-
class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false, default: {} # :internal:
|
12
|
-
end
|
13
|
-
|
11
|
+
# = Active Record \Attributes
|
14
12
|
module ClassMethods
|
15
|
-
|
13
|
+
# :method: attribute
|
16
14
|
# :call-seq: attribute(name, cast_type = nil, **options)
|
17
15
|
#
|
18
16
|
# Defines an attribute with a type on this model. It will override the
|
@@ -27,15 +25,17 @@ module ActiveRecord
|
|
27
25
|
# column which this will persist to.
|
28
26
|
#
|
29
27
|
# +cast_type+ A symbol such as +:string+ or +:integer+, or a type object
|
30
|
-
# to be used for this attribute.
|
31
|
-
#
|
28
|
+
# to be used for this attribute. If this parameter is not passed, the previously
|
29
|
+
# defined type (if any) will be used.
|
30
|
+
# Otherwise, the type will be ActiveModel::Type::Value.
|
31
|
+
# See the examples below for more information about providing custom type objects.
|
32
32
|
#
|
33
33
|
# ==== Options
|
34
34
|
#
|
35
35
|
# The following options are accepted:
|
36
36
|
#
|
37
37
|
# +default+ The default value to use when no value is provided. If this option
|
38
|
-
# is not passed, the
|
38
|
+
# is not passed, the previously defined default value (if any) on the superclass or in the schema will be used.
|
39
39
|
# Otherwise, the default will be +nil+.
|
40
40
|
#
|
41
41
|
# +array+ (PostgreSQL only) specifies that the type should be an array (see the
|
@@ -137,7 +137,7 @@ module ActiveRecord
|
|
137
137
|
# expected API. It is recommended that your type objects inherit from an
|
138
138
|
# existing type, or from ActiveRecord::Type::Value
|
139
139
|
#
|
140
|
-
# class
|
140
|
+
# class PriceType < ActiveRecord::Type::Integer
|
141
141
|
# def cast(value)
|
142
142
|
# if !value.kind_of?(Numeric) && value.include?('$')
|
143
143
|
# price_in_dollars = value.gsub(/\$/, '').to_f
|
@@ -149,11 +149,11 @@ module ActiveRecord
|
|
149
149
|
# end
|
150
150
|
#
|
151
151
|
# # config/initializers/types.rb
|
152
|
-
# ActiveRecord::Type.register(:
|
152
|
+
# ActiveRecord::Type.register(:price, PriceType)
|
153
153
|
#
|
154
154
|
# # app/models/store_listing.rb
|
155
155
|
# class StoreListing < ActiveRecord::Base
|
156
|
-
# attribute :price_in_cents, :
|
156
|
+
# attribute :price_in_cents, :price
|
157
157
|
# end
|
158
158
|
#
|
159
159
|
# store_listing = StoreListing.new(price_in_cents: '$10.00')
|
@@ -173,7 +173,7 @@ module ActiveRecord
|
|
173
173
|
# class Money < Struct.new(:amount, :currency)
|
174
174
|
# end
|
175
175
|
#
|
176
|
-
# class
|
176
|
+
# class PriceType < ActiveRecord::Type::Value
|
177
177
|
# def initialize(currency_converter:)
|
178
178
|
# @currency_converter = currency_converter
|
179
179
|
# end
|
@@ -188,19 +188,19 @@ module ActiveRecord
|
|
188
188
|
# end
|
189
189
|
#
|
190
190
|
# # config/initializers/types.rb
|
191
|
-
# ActiveRecord::Type.register(:
|
191
|
+
# ActiveRecord::Type.register(:price, PriceType)
|
192
192
|
#
|
193
193
|
# # app/models/product.rb
|
194
194
|
# class Product < ActiveRecord::Base
|
195
195
|
# currency_converter = ConversionRatesFromTheInternet.new
|
196
|
-
# attribute :price_in_bitcoins, :
|
196
|
+
# attribute :price_in_bitcoins, :price, currency_converter: currency_converter
|
197
197
|
# end
|
198
198
|
#
|
199
199
|
# Product.where(price_in_bitcoins: Money.new(5, "USD"))
|
200
|
-
# #
|
200
|
+
# # SELECT * FROM products WHERE price_in_bitcoins = 0.02230
|
201
201
|
#
|
202
202
|
# Product.where(price_in_bitcoins: Money.new(5, "GBP"))
|
203
|
-
# #
|
203
|
+
# # SELECT * FROM products WHERE price_in_bitcoins = 0.03412
|
204
204
|
#
|
205
205
|
# ==== Dirty Tracking
|
206
206
|
#
|
@@ -208,20 +208,12 @@ module ActiveRecord
|
|
208
208
|
# tracking is performed. The methods +changed?+ and +changed_in_place?+
|
209
209
|
# will be called from ActiveModel::Dirty. See the documentation for those
|
210
210
|
# methods in ActiveModel::Type::Value for more details.
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
self.attributes_to_define_after_schema_loads =
|
216
|
-
attributes_to_define_after_schema_loads.merge(
|
217
|
-
name => [cast_type || block, options]
|
218
|
-
)
|
219
|
-
end
|
211
|
+
#
|
212
|
+
#--
|
213
|
+
# Implemented by ActiveModel::AttributeRegistration#attribute.
|
220
214
|
|
221
|
-
# This
|
222
|
-
#
|
223
|
-
# waiting for the schema to load. Automatic schema detection and
|
224
|
-
# ClassMethods#attribute both call this under the hood. While this method
|
215
|
+
# This API only accepts type objects, and will do its work immediately instead of
|
216
|
+
# waiting for the schema to load. While this method
|
225
217
|
# is provided so it can be used by plugin authors, application code
|
226
218
|
# should probably use ClassMethods#attribute.
|
227
219
|
#
|
@@ -246,13 +238,38 @@ module ActiveRecord
|
|
246
238
|
define_default_attribute(name, default, cast_type, from_user: user_provided_default)
|
247
239
|
end
|
248
240
|
|
249
|
-
def
|
250
|
-
|
251
|
-
|
252
|
-
|
241
|
+
def _default_attributes # :nodoc:
|
242
|
+
@default_attributes ||= begin
|
243
|
+
attributes_hash = with_connection do |connection|
|
244
|
+
columns_hash.transform_values do |column|
|
245
|
+
ActiveModel::Attribute.from_database(column.name, column.default, type_for_column(connection, column))
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
attribute_set = ActiveModel::AttributeSet.new(attributes_hash)
|
250
|
+
apply_pending_attribute_modifications(attribute_set)
|
251
|
+
attribute_set
|
253
252
|
end
|
254
253
|
end
|
255
254
|
|
255
|
+
##
|
256
|
+
# :method: type_for_attribute
|
257
|
+
# :call-seq: type_for_attribute(attribute_name, &block)
|
258
|
+
#
|
259
|
+
# See ActiveModel::Attributes::ClassMethods#type_for_attribute.
|
260
|
+
#
|
261
|
+
# This method will access the database and load the model's schema if
|
262
|
+
# necessary.
|
263
|
+
#--
|
264
|
+
# Implemented by ActiveModel::AttributeRegistration::ClassMethods#type_for_attribute.
|
265
|
+
|
266
|
+
##
|
267
|
+
protected
|
268
|
+
def reload_schema_from_cache(*)
|
269
|
+
reset_default_attributes!
|
270
|
+
super
|
271
|
+
end
|
272
|
+
|
256
273
|
private
|
257
274
|
NO_DEFAULT_PROVIDED = Object.new # :nodoc:
|
258
275
|
private_constant :NO_DEFAULT_PROVIDED
|
@@ -273,30 +290,16 @@ module ActiveRecord
|
|
273
290
|
_default_attributes[name] = default_attribute
|
274
291
|
end
|
275
292
|
|
276
|
-
def
|
277
|
-
|
278
|
-
|
279
|
-
default.with_defaults!(default: options[:default]) if options&.key?(:default)
|
280
|
-
|
281
|
-
attribute(attr_name, **default) do |cast_type|
|
282
|
-
if type && !type.is_a?(Proc)
|
283
|
-
cast_type = _lookup_cast_type(attr_name, type, options)
|
284
|
-
end
|
293
|
+
def reset_default_attributes
|
294
|
+
reload_schema_from_cache
|
295
|
+
end
|
285
296
|
|
286
|
-
|
287
|
-
|
297
|
+
def resolve_type_name(name, **options)
|
298
|
+
Type.lookup(name, **options, adapter: Type.adapter_name_from(self))
|
288
299
|
end
|
289
300
|
|
290
|
-
def
|
291
|
-
|
292
|
-
when Symbol
|
293
|
-
adapter_name = ActiveRecord::Type.adapter_name_from(self)
|
294
|
-
ActiveRecord::Type.lookup(type, **options.except(:default), adapter: adapter_name)
|
295
|
-
when Proc
|
296
|
-
type[type_for_attribute(name)]
|
297
|
-
else
|
298
|
-
type || type_for_attribute(name)
|
299
|
-
end
|
301
|
+
def type_for_column(connection, column)
|
302
|
+
hook_attribute_type(column.name, super)
|
300
303
|
end
|
301
304
|
end
|
302
305
|
end
|