activerecord 6.1.6 → 7.1.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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +1627 -983
 - data/MIT-LICENSE +1 -1
 - data/README.rdoc +18 -18
 - data/lib/active_record/aggregations.rb +17 -14
 - data/lib/active_record/association_relation.rb +1 -11
 - data/lib/active_record/associations/association.rb +50 -19
 - data/lib/active_record/associations/association_scope.rb +17 -12
 - data/lib/active_record/associations/belongs_to_association.rb +28 -9
 - data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
 - data/lib/active_record/associations/builder/association.rb +11 -5
 - data/lib/active_record/associations/builder/belongs_to.rb +40 -14
 - data/lib/active_record/associations/builder/collection_association.rb +10 -3
 - data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
 - data/lib/active_record/associations/builder/has_many.rb +3 -2
 - data/lib/active_record/associations/builder/has_one.rb +2 -1
 - data/lib/active_record/associations/builder/singular_association.rb +6 -2
 - data/lib/active_record/associations/collection_association.rb +35 -31
 - data/lib/active_record/associations/collection_proxy.rb +30 -15
 - data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
 - data/lib/active_record/associations/foreign_association.rb +10 -3
 - data/lib/active_record/associations/has_many_association.rb +28 -18
 - data/lib/active_record/associations/has_many_through_association.rb +12 -7
 - 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.rb +26 -16
 - data/lib/active_record/associations/preloader/association.rb +207 -52
 - data/lib/active_record/associations/preloader/batch.rb +48 -0
 - data/lib/active_record/associations/preloader/branch.rb +147 -0
 - data/lib/active_record/associations/preloader/through_association.rb +50 -14
 - data/lib/active_record/associations/preloader.rb +50 -121
 - data/lib/active_record/associations/singular_association.rb +9 -3
 - data/lib/active_record/associations/through_association.rb +25 -14
 - data/lib/active_record/associations.rb +439 -305
 - data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
 - data/lib/active_record/attribute_assignment.rb +1 -3
 - data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
 - data/lib/active_record/attribute_methods/dirty.rb +73 -22
 - data/lib/active_record/attribute_methods/primary_key.rb +78 -26
 - data/lib/active_record/attribute_methods/query.rb +31 -19
 - data/lib/active_record/attribute_methods/read.rb +25 -10
 - data/lib/active_record/attribute_methods/serialization.rb +194 -37
 - data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
 - data/lib/active_record/attribute_methods/write.rb +10 -13
 - data/lib/active_record/attribute_methods.rb +121 -40
 - data/lib/active_record/attributes.rb +27 -38
 - data/lib/active_record/autosave_association.rb +61 -30
 - data/lib/active_record/base.rb +25 -2
 - data/lib/active_record/callbacks.rb +18 -34
 - 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 -34
 - data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -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 +78 -0
 - data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
 - data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
 - data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
 - data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
 - data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
 - 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 +360 -138
 - data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
 - data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -149
 - data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
 - 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 +25 -134
 - data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
 - 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 +38 -14
 - data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
 - data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
 - data/lib/active_record/connection_adapters/pool_config.rb +20 -11
 - 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 +89 -52
 - data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
 - 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/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.rb +2 -0
 - data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
 - 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 +153 -3
 - data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
 - data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +394 -74
 - data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
 - data/lib/active_record/connection_adapters/postgresql_adapter.rb +509 -247
 - data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
 - data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
 - data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
 - data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
 - data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
 - data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
 - data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
 - 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 +254 -0
 - data/lib/active_record/connection_adapters.rb +9 -6
 - data/lib/active_record/connection_handling.rb +107 -136
 - data/lib/active_record/core.rb +202 -223
 - data/lib/active_record/counter_cache.rb +46 -25
 - data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
 - data/lib/active_record/database_configurations/database_config.rb +21 -12
 - data/lib/active_record/database_configurations/hash_config.rb +84 -16
 - data/lib/active_record/database_configurations/url_config.rb +18 -12
 - data/lib/active_record/database_configurations.rb +95 -59
 - data/lib/active_record/delegated_type.rb +61 -15
 - data/lib/active_record/deprecator.rb +7 -0
 - data/lib/active_record/destroy_association_async_job.rb +3 -1
 - data/lib/active_record/disable_joins_association_relation.rb +39 -0
 - data/lib/active_record/dynamic_matchers.rb +1 -1
 - 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 +224 -0
 - data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -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 +155 -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_serializer.rb +92 -0
 - data/lib/active_record/encryption/null_encryptor.rb +21 -0
 - data/lib/active_record/encryption/properties.rb +76 -0
 - data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
 - data/lib/active_record/encryption/scheme.rb +96 -0
 - data/lib/active_record/encryption.rb +56 -0
 - data/lib/active_record/enum.rb +154 -63
 - data/lib/active_record/errors.rb +171 -15
 - data/lib/active_record/explain.rb +23 -3
 - 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 +131 -86
 - data/lib/active_record/future_result.rb +164 -0
 - data/lib/active_record/gem_version.rb +3 -3
 - data/lib/active_record/inheritance.rb +81 -29
 - data/lib/active_record/insert_all.rb +135 -22
 - data/lib/active_record/integration.rb +11 -10
 - data/lib/active_record/internal_metadata.rb +119 -33
 - data/lib/active_record/legacy_yaml_adapter.rb +2 -39
 - data/lib/active_record/locking/optimistic.rb +36 -21
 - data/lib/active_record/locking/pessimistic.rb +15 -6
 - data/lib/active_record/log_subscriber.rb +52 -19
 - data/lib/active_record/marshalling.rb +56 -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 +112 -14
 - data/lib/active_record/migration/compatibility.rb +221 -48
 - data/lib/active_record/migration/default_strategy.rb +23 -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 +358 -171
 - data/lib/active_record/model_schema.rb +120 -101
 - data/lib/active_record/nested_attributes.rb +37 -18
 - data/lib/active_record/no_touching.rb +3 -3
 - data/lib/active_record/normalization.rb +167 -0
 - data/lib/active_record/persistence.rb +405 -85
 - data/lib/active_record/promise.rb +84 -0
 - data/lib/active_record/query_cache.rb +3 -21
 - data/lib/active_record/query_logs.rb +174 -0
 - data/lib/active_record/query_logs_formatter.rb +41 -0
 - data/lib/active_record/querying.rb +29 -6
 - data/lib/active_record/railtie.rb +219 -43
 - data/lib/active_record/railties/controller_runtime.rb +13 -9
 - data/lib/active_record/railties/databases.rake +188 -252
 - 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 +241 -80
 - data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
 - data/lib/active_record/relation/batches.rb +192 -63
 - data/lib/active_record/relation/calculations.rb +219 -90
 - data/lib/active_record/relation/delegation.rb +27 -13
 - data/lib/active_record/relation/finder_methods.rb +108 -51
 - data/lib/active_record/relation/merger.rb +22 -13
 - data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
 - data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
 - data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
 - data/lib/active_record/relation/predicate_builder.rb +27 -20
 - data/lib/active_record/relation/query_attribute.rb +30 -12
 - data/lib/active_record/relation/query_methods.rb +654 -127
 - data/lib/active_record/relation/record_fetch_warning.rb +7 -9
 - data/lib/active_record/relation/spawn_methods.rb +20 -3
 - data/lib/active_record/relation/where_clause.rb +10 -19
 - data/lib/active_record/relation.rb +262 -120
 - data/lib/active_record/result.rb +37 -11
 - data/lib/active_record/runtime_registry.rb +18 -13
 - data/lib/active_record/sanitization.rb +65 -20
 - data/lib/active_record/schema.rb +36 -22
 - data/lib/active_record/schema_dumper.rb +73 -24
 - data/lib/active_record/schema_migration.rb +68 -33
 - data/lib/active_record/scoping/default.rb +72 -15
 - data/lib/active_record/scoping/named.rb +5 -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 +10 -8
 - data/lib/active_record/store.rb +16 -11
 - data/lib/active_record/suppressor.rb +13 -15
 - data/lib/active_record/table_metadata.rb +16 -3
 - data/lib/active_record/tasks/database_tasks.rb +225 -136
 - 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 +15 -7
 - data/lib/active_record/test_databases.rb +1 -1
 - data/lib/active_record/test_fixtures.rb +123 -99
 - data/lib/active_record/timestamp.rb +29 -18
 - data/lib/active_record/token_for.rb +113 -0
 - data/lib/active_record/touch_later.rb +11 -6
 - data/lib/active_record/transactions.rb +48 -27
 - data/lib/active_record/translation.rb +3 -3
 - 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 -5
 - 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/validations/absence.rb +1 -1
 - data/lib/active_record/validations/associated.rb +4 -4
 - 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 +51 -6
 - data/lib/active_record/validations.rb +8 -4
 - data/lib/active_record/version.rb +1 -1
 - data/lib/active_record.rb +335 -32
 - data/lib/arel/attributes/attribute.rb +0 -8
 - 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/and.rb +4 -0
 - data/lib/arel/nodes/binary.rb +6 -1
 - data/lib/arel/nodes/bound_sql_literal.rb +61 -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/node.rb +111 -2
 - 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 +6 -0
 - data/lib/arel/nodes/table_alias.rb +4 -0
 - data/lib/arel/nodes/update_statement.rb +8 -3
 - data/lib/arel/nodes.rb +5 -0
 - data/lib/arel/predications.rb +13 -3
 - data/lib/arel/select_manager.rb +10 -4
 - data/lib/arel/table.rb +9 -6
 - data/lib/arel/tree_manager.rb +0 -12
 - data/lib/arel/update_manager.rb +18 -4
 - data/lib/arel/visitors/dot.rb +80 -90
 - data/lib/arel/visitors/mysql.rb +16 -3
 - data/lib/arel/visitors/postgresql.rb +0 -10
 - data/lib/arel/visitors/to_sql.rb +139 -19
 - data/lib/arel/visitors/visitor.rb +2 -2
 - data/lib/arel.rb +18 -3
 - 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.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 +93 -13
 - data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
 - data/lib/active_record/null_relation.rb +0 -67
 
| 
         @@ -6,6 +6,13 @@ module ActiveRecord 
     | 
|
| 
       6 
6 
     | 
    
         
             
              module ModelSchema
         
     | 
| 
       7 
7 
     | 
    
         
             
                extend ActiveSupport::Concern
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
      
 9 
     | 
    
         
            +
                ##
         
     | 
| 
      
 10 
     | 
    
         
            +
                # :method: id_value
         
     | 
| 
      
 11 
     | 
    
         
            +
                # :call-seq: id_value
         
     | 
| 
      
 12 
     | 
    
         
            +
                #
         
     | 
| 
      
 13 
     | 
    
         
            +
                # Returns the underlying column value for a column named "id". Useful when defining
         
     | 
| 
      
 14 
     | 
    
         
            +
                # a composite primary key including an "id" column so that the value is readable.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
       9 
16 
     | 
    
         
             
                ##
         
     | 
| 
       10 
17 
     | 
    
         
             
                # :singleton-method: primary_key_prefix_type
         
     | 
| 
       11 
18 
     | 
    
         
             
                # :call-seq: primary_key_prefix_type
         
     | 
| 
         @@ -126,9 +133,29 @@ module ActiveRecord 
     | 
|
| 
       126 
133 
     | 
    
         
             
                # +:immutable_string+. This setting does not affect the behavior of
         
     | 
| 
       127 
134 
     | 
    
         
             
                # <tt>attribute :foo, :string</tt>. Defaults to false.
         
     | 
| 
       128 
135 
     | 
    
         | 
| 
       129 
     | 
    
         
            -
                 
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
      
 136 
     | 
    
         
            +
                ##
         
     | 
| 
      
 137 
     | 
    
         
            +
                # :singleton-method: inheritance_column
         
     | 
| 
      
 138 
     | 
    
         
            +
                # :call-seq: inheritance_column
         
     | 
| 
      
 139 
     | 
    
         
            +
                #
         
     | 
| 
      
 140 
     | 
    
         
            +
                # The name of the table column which stores the class name on single-table
         
     | 
| 
      
 141 
     | 
    
         
            +
                # inheritance situations.
         
     | 
| 
      
 142 
     | 
    
         
            +
                #
         
     | 
| 
      
 143 
     | 
    
         
            +
                # The default inheritance column name is +type+, which means it's a
         
     | 
| 
      
 144 
     | 
    
         
            +
                # reserved word inside Active Record. To be able to use single-table
         
     | 
| 
      
 145 
     | 
    
         
            +
                # inheritance with another column name, or to use the column +type+ in
         
     | 
| 
      
 146 
     | 
    
         
            +
                # your own model for something else, you can set +inheritance_column+:
         
     | 
| 
      
 147 
     | 
    
         
            +
                #
         
     | 
| 
      
 148 
     | 
    
         
            +
                #     self.inheritance_column = 'zoink'
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                ##
         
     | 
| 
      
 151 
     | 
    
         
            +
                # :singleton-method: inheritance_column=
         
     | 
| 
      
 152 
     | 
    
         
            +
                # :call-seq: inheritance_column=(column)
         
     | 
| 
      
 153 
     | 
    
         
            +
                #
         
     | 
| 
      
 154 
     | 
    
         
            +
                # Defines the name of the table column which will store the class name on single-table
         
     | 
| 
      
 155 
     | 
    
         
            +
                # inheritance situations.
         
     | 
| 
       131 
156 
     | 
    
         | 
| 
      
 157 
     | 
    
         
            +
                included do
         
     | 
| 
      
 158 
     | 
    
         
            +
                  class_attribute :primary_key_prefix_type, instance_writer: false
         
     | 
| 
       132 
159 
     | 
    
         
             
                  class_attribute :table_name_prefix, instance_writer: false, default: ""
         
     | 
| 
       133 
160 
     | 
    
         
             
                  class_attribute :table_name_suffix, instance_writer: false, default: ""
         
     | 
| 
       134 
161 
     | 
    
         
             
                  class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
         
     | 
| 
         @@ -137,8 +164,15 @@ module ActiveRecord 
     | 
|
| 
       137 
164 
     | 
    
         
             
                  class_attribute :implicit_order_column, instance_accessor: false
         
     | 
| 
       138 
165 
     | 
    
         
             
                  class_attribute :immutable_strings_by_default, instance_accessor: false
         
     | 
| 
       139 
166 
     | 
    
         | 
| 
      
 167 
     | 
    
         
            +
                  class_attribute :inheritance_column, instance_accessor: false, default: "type"
         
     | 
| 
      
 168 
     | 
    
         
            +
                  singleton_class.class_eval do
         
     | 
| 
      
 169 
     | 
    
         
            +
                    alias_method :_inheritance_column=, :inheritance_column=
         
     | 
| 
      
 170 
     | 
    
         
            +
                    private :_inheritance_column=
         
     | 
| 
      
 171 
     | 
    
         
            +
                    alias_method :inheritance_column=, :real_inheritance_column=
         
     | 
| 
      
 172 
     | 
    
         
            +
                  end
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
       140 
174 
     | 
    
         
             
                  self.protected_environments = ["production"]
         
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
       142 
176 
     | 
    
         
             
                  self.ignored_columns = [].freeze
         
     | 
| 
       143 
177 
     | 
    
         | 
| 
       144 
178 
     | 
    
         
             
                  delegate :type_for_attribute, :column_for_attribute, to: :class
         
     | 
| 
         @@ -153,8 +187,9 @@ module ActiveRecord 
     | 
|
| 
       153 
187 
     | 
    
         
             
                #   artists, records => artists_records
         
     | 
| 
       154 
188 
     | 
    
         
             
                #   records, artists => artists_records
         
     | 
| 
       155 
189 
     | 
    
         
             
                #   music_artists, music_records => music_artists_records
         
     | 
| 
      
 190 
     | 
    
         
            +
                #   music.artists, music.records => music.artists_records
         
     | 
| 
       156 
191 
     | 
    
         
             
                def self.derive_join_table_name(first_table, second_table) # :nodoc:
         
     | 
| 
       157 
     | 
    
         
            -
                  [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
         
     | 
| 
      
 192 
     | 
    
         
            +
                  [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*[_.])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
         
     | 
| 
       158 
193 
     | 
    
         
             
                end
         
     | 
| 
       159 
194 
     | 
    
         | 
| 
       160 
195 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
         @@ -197,6 +232,21 @@ module ActiveRecord 
     | 
|
| 
       197 
232 
     | 
    
         
             
                  # the table name guess for an Invoice class becomes "myapp_invoices".
         
     | 
| 
       198 
233 
     | 
    
         
             
                  # Invoice::Lineitem becomes "myapp_invoice_lineitems".
         
     | 
| 
       199 
234 
     | 
    
         
             
                  #
         
     | 
| 
      
 235 
     | 
    
         
            +
                  # Active Model Naming's +model_name+ is the base name used to guess the
         
     | 
| 
      
 236 
     | 
    
         
            +
                  # table name. In case a custom Active Model Name is defined, it will be
         
     | 
| 
      
 237 
     | 
    
         
            +
                  # used for the table name as well:
         
     | 
| 
      
 238 
     | 
    
         
            +
                  #
         
     | 
| 
      
 239 
     | 
    
         
            +
                  #   class PostRecord < ActiveRecord::Base
         
     | 
| 
      
 240 
     | 
    
         
            +
                  #     class << self
         
     | 
| 
      
 241 
     | 
    
         
            +
                  #       def model_name
         
     | 
| 
      
 242 
     | 
    
         
            +
                  #         ActiveModel::Name.new(self, nil, "Post")
         
     | 
| 
      
 243 
     | 
    
         
            +
                  #       end
         
     | 
| 
      
 244 
     | 
    
         
            +
                  #     end
         
     | 
| 
      
 245 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 246 
     | 
    
         
            +
                  #
         
     | 
| 
      
 247 
     | 
    
         
            +
                  #   PostRecord.table_name
         
     | 
| 
      
 248 
     | 
    
         
            +
                  #   # => "posts"
         
     | 
| 
      
 249 
     | 
    
         
            +
                  #
         
     | 
| 
       200 
250 
     | 
    
         
             
                  # You can also set your own table name explicitly:
         
     | 
| 
       201 
251 
     | 
    
         
             
                  #
         
     | 
| 
       202 
252 
     | 
    
         
             
                  #   class Mouse < ActiveRecord::Base
         
     | 
| 
         @@ -233,9 +283,11 @@ module ActiveRecord 
     | 
|
| 
       233 
283 
     | 
    
         
             
                  end
         
     | 
| 
       234 
284 
     | 
    
         | 
| 
       235 
285 
     | 
    
         
             
                  # Computes the table name, (re)sets it internally, and returns it.
         
     | 
| 
       236 
     | 
    
         
            -
                  def reset_table_name  
     | 
| 
       237 
     | 
    
         
            -
                    self.table_name = if  
     | 
| 
       238 
     | 
    
         
            -
                       
     | 
| 
      
 286 
     | 
    
         
            +
                  def reset_table_name # :nodoc:
         
     | 
| 
      
 287 
     | 
    
         
            +
                    self.table_name = if self == Base
         
     | 
| 
      
 288 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 289 
     | 
    
         
            +
                    elsif abstract_class?
         
     | 
| 
      
 290 
     | 
    
         
            +
                      superclass.table_name
         
     | 
| 
       239 
291 
     | 
    
         
             
                    elsif superclass.abstract_class?
         
     | 
| 
       240 
292 
     | 
    
         
             
                      superclass.table_name || compute_table_name
         
     | 
| 
       241 
293 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -243,11 +295,11 @@ module ActiveRecord 
     | 
|
| 
       243 
295 
     | 
    
         
             
                    end
         
     | 
| 
       244 
296 
     | 
    
         
             
                  end
         
     | 
| 
       245 
297 
     | 
    
         | 
| 
       246 
     | 
    
         
            -
                  def full_table_name_prefix  
     | 
| 
      
 298 
     | 
    
         
            +
                  def full_table_name_prefix # :nodoc:
         
     | 
| 
       247 
299 
     | 
    
         
             
                    (module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
         
     | 
| 
       248 
300 
     | 
    
         
             
                  end
         
     | 
| 
       249 
301 
     | 
    
         | 
| 
       250 
     | 
    
         
            -
                  def full_table_name_suffix  
     | 
| 
      
 302 
     | 
    
         
            +
                  def full_table_name_suffix # :nodoc:
         
     | 
| 
       251 
303 
     | 
    
         
             
                    (module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
         
     | 
| 
       252 
304 
     | 
    
         
             
                  end
         
     | 
| 
       253 
305 
     | 
    
         | 
| 
         @@ -266,33 +318,14 @@ module ActiveRecord 
     | 
|
| 
       266 
318 
     | 
    
         
             
                    @protected_environments = environments.map(&:to_s)
         
     | 
| 
       267 
319 
     | 
    
         
             
                  end
         
     | 
| 
       268 
320 
     | 
    
         | 
| 
       269 
     | 
    
         
            -
                   
     | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
       271 
     | 
    
         
            -
                  #
         
     | 
| 
       272 
     | 
    
         
            -
                  # The default inheritance column name is +type+, which means it's a
         
     | 
| 
       273 
     | 
    
         
            -
                  # reserved word inside Active Record. To be able to use single-table
         
     | 
| 
       274 
     | 
    
         
            -
                  # inheritance with another column name, or to use the column +type+ in
         
     | 
| 
       275 
     | 
    
         
            -
                  # your own model for something else, you can set +inheritance_column+:
         
     | 
| 
       276 
     | 
    
         
            -
                  #
         
     | 
| 
       277 
     | 
    
         
            -
                  #     self.inheritance_column = 'zoink'
         
     | 
| 
       278 
     | 
    
         
            -
                  def inheritance_column
         
     | 
| 
       279 
     | 
    
         
            -
                    (@inheritance_column ||= nil) || superclass.inheritance_column
         
     | 
| 
       280 
     | 
    
         
            -
                  end
         
     | 
| 
       281 
     | 
    
         
            -
             
     | 
| 
       282 
     | 
    
         
            -
                  # Sets the value of inheritance_column
         
     | 
| 
       283 
     | 
    
         
            -
                  def inheritance_column=(value)
         
     | 
| 
       284 
     | 
    
         
            -
                    @inheritance_column = value.to_s
         
     | 
| 
       285 
     | 
    
         
            -
                    @explicit_inheritance_column = true
         
     | 
| 
      
 321 
     | 
    
         
            +
                  def real_inheritance_column=(value) # :nodoc:
         
     | 
| 
      
 322 
     | 
    
         
            +
                    self._inheritance_column = value.to_s
         
     | 
| 
       286 
323 
     | 
    
         
             
                  end
         
     | 
| 
       287 
324 
     | 
    
         | 
| 
       288 
325 
     | 
    
         
             
                  # The list of columns names the model should ignore. Ignored columns won't have attribute
         
     | 
| 
       289 
326 
     | 
    
         
             
                  # accessors defined, and won't be referenced in SQL queries.
         
     | 
| 
       290 
327 
     | 
    
         
             
                  def ignored_columns
         
     | 
| 
       291 
     | 
    
         
            -
                     
     | 
| 
       292 
     | 
    
         
            -
                      @ignored_columns
         
     | 
| 
       293 
     | 
    
         
            -
                    else
         
     | 
| 
       294 
     | 
    
         
            -
                      superclass.ignored_columns
         
     | 
| 
       295 
     | 
    
         
            -
                    end
         
     | 
| 
      
 328 
     | 
    
         
            +
                    @ignored_columns || superclass.ignored_columns
         
     | 
| 
       296 
329 
     | 
    
         
             
                  end
         
     | 
| 
       297 
330 
     | 
    
         | 
| 
       298 
331 
     | 
    
         
             
                  # Sets the columns names the model should ignore. Ignored columns won't have attribute
         
     | 
| 
         @@ -313,7 +346,7 @@ module ActiveRecord 
     | 
|
| 
       313 
346 
     | 
    
         
             
                  #     #   name       :string, limit: 255
         
     | 
| 
       314 
347 
     | 
    
         
             
                  #     #   category   :string, limit: 255
         
     | 
| 
       315 
348 
     | 
    
         
             
                  #
         
     | 
| 
       316 
     | 
    
         
            -
                  #     self.ignored_columns  
     | 
| 
      
 349 
     | 
    
         
            +
                  #     self.ignored_columns += [:category]
         
     | 
| 
       317 
350 
     | 
    
         
             
                  #   end
         
     | 
| 
       318 
351 
     | 
    
         
             
                  #
         
     | 
| 
       319 
352 
     | 
    
         
             
                  # The schema still contains "category", but now the model omits it, so any meta-driven code or
         
     | 
| 
         @@ -339,7 +372,7 @@ module ActiveRecord 
     | 
|
| 
       339 
372 
     | 
    
         
             
                    end
         
     | 
| 
       340 
373 
     | 
    
         
             
                  end
         
     | 
| 
       341 
374 
     | 
    
         | 
| 
       342 
     | 
    
         
            -
                  def reset_sequence_name  
     | 
| 
      
 375 
     | 
    
         
            +
                  def reset_sequence_name # :nodoc:
         
     | 
| 
       343 
376 
     | 
    
         
             
                    @explicit_sequence_name = false
         
     | 
| 
       344 
377 
     | 
    
         
             
                    @sequence_name          = connection.default_sequence_name(table_name, primary_key)
         
     | 
| 
       345 
378 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -398,6 +431,12 @@ module ActiveRecord 
     | 
|
| 
       398 
431 
     | 
    
         
             
                    @columns ||= columns_hash.values.freeze
         
     | 
| 
       399 
432 
     | 
    
         
             
                  end
         
     | 
| 
       400 
433 
     | 
    
         | 
| 
      
 434 
     | 
    
         
            +
                  def _returning_columns_for_insert # :nodoc:
         
     | 
| 
      
 435 
     | 
    
         
            +
                    @_returning_columns_for_insert ||= columns.filter_map do |c|
         
     | 
| 
      
 436 
     | 
    
         
            +
                      c.name if connection.return_value_after_insert?(c)
         
     | 
| 
      
 437 
     | 
    
         
            +
                    end
         
     | 
| 
      
 438 
     | 
    
         
            +
                  end
         
     | 
| 
      
 439 
     | 
    
         
            +
             
     | 
| 
       401 
440 
     | 
    
         
             
                  def attribute_types # :nodoc:
         
     | 
| 
       402 
441 
     | 
    
         
             
                    load_schema
         
     | 
| 
       403 
442 
     | 
    
         
             
                    @attribute_types ||= Hash.new(Type.default_value)
         
     | 
| 
         @@ -430,7 +469,7 @@ module ActiveRecord 
     | 
|
| 
       430 
469 
     | 
    
         
             
                  end
         
     | 
| 
       431 
470 
     | 
    
         | 
| 
       432 
471 
     | 
    
         
             
                  # Returns the column object for the named attribute.
         
     | 
| 
       433 
     | 
    
         
            -
                  # Returns an  
     | 
| 
      
 472 
     | 
    
         
            +
                  # Returns an ActiveRecord::ConnectionAdapters::NullColumn if the
         
     | 
| 
       434 
473 
     | 
    
         
             
                  # named attribute does not exist.
         
     | 
| 
       435 
474 
     | 
    
         
             
                  #
         
     | 
| 
       436 
475 
     | 
    
         
             
                  #   class Person < ActiveRecord::Base
         
     | 
| 
         @@ -486,9 +525,9 @@ module ActiveRecord 
     | 
|
| 
       486 
525 
     | 
    
         
             
                  #
         
     | 
| 
       487 
526 
     | 
    
         
             
                  # The most common usage pattern for this method is probably in a migration,
         
     | 
| 
       488 
527 
     | 
    
         
             
                  # when just after creating a table you want to populate it with some default
         
     | 
| 
       489 
     | 
    
         
            -
                  # values,  
     | 
| 
      
 528 
     | 
    
         
            +
                  # values, e.g.:
         
     | 
| 
       490 
529 
     | 
    
         
             
                  #
         
     | 
| 
       491 
     | 
    
         
            -
                  #  class CreateJobLevels < ActiveRecord::Migration[ 
     | 
| 
      
 530 
     | 
    
         
            +
                  #  class CreateJobLevels < ActiveRecord::Migration[7.1]
         
     | 
| 
       492 
531 
     | 
    
         
             
                  #    def up
         
     | 
| 
       493 
532 
     | 
    
         
             
                  #      create_table :job_levels do |t|
         
     | 
| 
       494 
533 
     | 
    
         
             
                  #        t.integer :id
         
     | 
| 
         @@ -516,35 +555,61 @@ module ActiveRecord 
     | 
|
| 
       516 
555 
     | 
    
         
             
                    initialize_find_by_cache
         
     | 
| 
       517 
556 
     | 
    
         
             
                  end
         
     | 
| 
       518 
557 
     | 
    
         | 
| 
      
 558 
     | 
    
         
            +
                  def load_schema # :nodoc:
         
     | 
| 
      
 559 
     | 
    
         
            +
                    return if schema_loaded?
         
     | 
| 
      
 560 
     | 
    
         
            +
                    @load_schema_monitor.synchronize do
         
     | 
| 
      
 561 
     | 
    
         
            +
                      return if @columns_hash
         
     | 
| 
      
 562 
     | 
    
         
            +
             
     | 
| 
      
 563 
     | 
    
         
            +
                      load_schema!
         
     | 
| 
      
 564 
     | 
    
         
            +
             
     | 
| 
      
 565 
     | 
    
         
            +
                      @schema_loaded = true
         
     | 
| 
      
 566 
     | 
    
         
            +
                    rescue
         
     | 
| 
      
 567 
     | 
    
         
            +
                      reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
         
     | 
| 
      
 568 
     | 
    
         
            +
                      raise
         
     | 
| 
      
 569 
     | 
    
         
            +
                    end
         
     | 
| 
      
 570 
     | 
    
         
            +
                  end
         
     | 
| 
      
 571 
     | 
    
         
            +
             
     | 
| 
       519 
572 
     | 
    
         
             
                  protected
         
     | 
| 
       520 
573 
     | 
    
         
             
                    def initialize_load_schema_monitor
         
     | 
| 
       521 
574 
     | 
    
         
             
                      @load_schema_monitor = Monitor.new
         
     | 
| 
       522 
575 
     | 
    
         
             
                    end
         
     | 
| 
       523 
576 
     | 
    
         | 
| 
      
 577 
     | 
    
         
            +
                    def reload_schema_from_cache(recursive = true)
         
     | 
| 
      
 578 
     | 
    
         
            +
                      @_returning_columns_for_insert = nil
         
     | 
| 
      
 579 
     | 
    
         
            +
                      @arel_table = nil
         
     | 
| 
      
 580 
     | 
    
         
            +
                      @column_names = nil
         
     | 
| 
      
 581 
     | 
    
         
            +
                      @symbol_column_to_string_name_hash = nil
         
     | 
| 
      
 582 
     | 
    
         
            +
                      @attribute_types = nil
         
     | 
| 
      
 583 
     | 
    
         
            +
                      @content_columns = nil
         
     | 
| 
      
 584 
     | 
    
         
            +
                      @default_attributes = nil
         
     | 
| 
      
 585 
     | 
    
         
            +
                      @column_defaults = nil
         
     | 
| 
      
 586 
     | 
    
         
            +
                      @attributes_builder = nil
         
     | 
| 
      
 587 
     | 
    
         
            +
                      @columns = nil
         
     | 
| 
      
 588 
     | 
    
         
            +
                      @columns_hash = nil
         
     | 
| 
      
 589 
     | 
    
         
            +
                      @schema_loaded = false
         
     | 
| 
      
 590 
     | 
    
         
            +
                      @attribute_names = nil
         
     | 
| 
      
 591 
     | 
    
         
            +
                      @yaml_encoder = nil
         
     | 
| 
      
 592 
     | 
    
         
            +
                      if recursive
         
     | 
| 
      
 593 
     | 
    
         
            +
                        subclasses.each do |descendant|
         
     | 
| 
      
 594 
     | 
    
         
            +
                          descendant.send(:reload_schema_from_cache)
         
     | 
| 
      
 595 
     | 
    
         
            +
                        end
         
     | 
| 
      
 596 
     | 
    
         
            +
                      end
         
     | 
| 
      
 597 
     | 
    
         
            +
                    end
         
     | 
| 
      
 598 
     | 
    
         
            +
             
     | 
| 
       524 
599 
     | 
    
         
             
                  private
         
     | 
| 
       525 
600 
     | 
    
         
             
                    def inherited(child_class)
         
     | 
| 
       526 
601 
     | 
    
         
             
                      super
         
     | 
| 
       527 
602 
     | 
    
         
             
                      child_class.initialize_load_schema_monitor
         
     | 
| 
      
 603 
     | 
    
         
            +
                      child_class.reload_schema_from_cache(false)
         
     | 
| 
      
 604 
     | 
    
         
            +
                      child_class.class_eval do
         
     | 
| 
      
 605 
     | 
    
         
            +
                        @ignored_columns = nil
         
     | 
| 
      
 606 
     | 
    
         
            +
                      end
         
     | 
| 
       528 
607 
     | 
    
         
             
                    end
         
     | 
| 
       529 
608 
     | 
    
         | 
| 
       530 
609 
     | 
    
         
             
                    def schema_loaded?
         
     | 
| 
       531 
610 
     | 
    
         
             
                      defined?(@schema_loaded) && @schema_loaded
         
     | 
| 
       532 
611 
     | 
    
         
             
                    end
         
     | 
| 
       533 
612 
     | 
    
         | 
| 
       534 
     | 
    
         
            -
                    def load_schema
         
     | 
| 
       535 
     | 
    
         
            -
                      return if schema_loaded?
         
     | 
| 
       536 
     | 
    
         
            -
                      @load_schema_monitor.synchronize do
         
     | 
| 
       537 
     | 
    
         
            -
                        return if defined?(@columns_hash) && @columns_hash
         
     | 
| 
       538 
     | 
    
         
            -
             
     | 
| 
       539 
     | 
    
         
            -
                        load_schema!
         
     | 
| 
       540 
     | 
    
         
            -
             
     | 
| 
       541 
     | 
    
         
            -
                        @schema_loaded = true
         
     | 
| 
       542 
     | 
    
         
            -
                      rescue
         
     | 
| 
       543 
     | 
    
         
            -
                        reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
         
     | 
| 
       544 
     | 
    
         
            -
                        raise
         
     | 
| 
       545 
     | 
    
         
            -
                      end
         
     | 
| 
       546 
     | 
    
         
            -
                    end
         
     | 
| 
       547 
     | 
    
         
            -
             
     | 
| 
       548 
613 
     | 
    
         
             
                    def load_schema!
         
     | 
| 
       549 
614 
     | 
    
         
             
                      unless table_name
         
     | 
| 
       550 
615 
     | 
    
         
             
                        raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
         
     | 
| 
         @@ -556,39 +621,19 @@ module ActiveRecord 
     | 
|
| 
       556 
621 
     | 
    
         
             
                      @columns_hash.each do |name, column|
         
     | 
| 
       557 
622 
     | 
    
         
             
                        type = connection.lookup_cast_type_from_column(column)
         
     | 
| 
       558 
623 
     | 
    
         
             
                        type = _convert_type_from_options(type)
         
     | 
| 
       559 
     | 
    
         
            -
                        warn_if_deprecated_type(column)
         
     | 
| 
       560 
624 
     | 
    
         
             
                        define_attribute(
         
     | 
| 
       561 
625 
     | 
    
         
             
                          name,
         
     | 
| 
       562 
626 
     | 
    
         
             
                          type,
         
     | 
| 
       563 
627 
     | 
    
         
             
                          default: column.default,
         
     | 
| 
       564 
628 
     | 
    
         
             
                          user_provided_default: false
         
     | 
| 
       565 
629 
     | 
    
         
             
                        )
         
     | 
| 
       566 
     | 
    
         
            -
             
     | 
| 
       567 
     | 
    
         
            -
                    end
         
     | 
| 
       568 
     | 
    
         
            -
             
     | 
| 
       569 
     | 
    
         
            -
                    def reload_schema_from_cache
         
     | 
| 
       570 
     | 
    
         
            -
                      @arel_table = nil
         
     | 
| 
       571 
     | 
    
         
            -
                      @column_names = nil
         
     | 
| 
       572 
     | 
    
         
            -
                      @symbol_column_to_string_name_hash = nil
         
     | 
| 
       573 
     | 
    
         
            -
                      @attribute_types = nil
         
     | 
| 
       574 
     | 
    
         
            -
                      @content_columns = nil
         
     | 
| 
       575 
     | 
    
         
            -
                      @default_attributes = nil
         
     | 
| 
       576 
     | 
    
         
            -
                      @column_defaults = nil
         
     | 
| 
       577 
     | 
    
         
            -
                      @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
         
     | 
| 
       578 
     | 
    
         
            -
                      @attributes_builder = nil
         
     | 
| 
       579 
     | 
    
         
            -
                      @columns = nil
         
     | 
| 
       580 
     | 
    
         
            -
                      @columns_hash = nil
         
     | 
| 
       581 
     | 
    
         
            -
                      @schema_loaded = false
         
     | 
| 
       582 
     | 
    
         
            -
                      @attribute_names = nil
         
     | 
| 
       583 
     | 
    
         
            -
                      @yaml_encoder = nil
         
     | 
| 
       584 
     | 
    
         
            -
                      direct_descendants.each do |descendant|
         
     | 
| 
       585 
     | 
    
         
            -
                        descendant.send(:reload_schema_from_cache)
         
     | 
| 
      
 630 
     | 
    
         
            +
                        alias_attribute :id_value, :id if name == "id"
         
     | 
| 
       586 
631 
     | 
    
         
             
                      end
         
     | 
| 
       587 
632 
     | 
    
         
             
                    end
         
     | 
| 
       588 
633 
     | 
    
         | 
| 
       589 
634 
     | 
    
         
             
                    # Guesses the table name, but does not decorate it with prefix and suffix information.
         
     | 
| 
       590 
     | 
    
         
            -
                    def undecorated_table_name( 
     | 
| 
       591 
     | 
    
         
            -
                      table_name =  
     | 
| 
      
 635 
     | 
    
         
            +
                    def undecorated_table_name(model_name)
         
     | 
| 
      
 636 
     | 
    
         
            +
                      table_name = model_name.to_s.demodulize.underscore
         
     | 
| 
       592 
637 
     | 
    
         
             
                      pluralize_table_names ? table_name.pluralize : table_name
         
     | 
| 
       593 
638 
     | 
    
         
             
                    end
         
     | 
| 
       594 
639 
     | 
    
         | 
| 
         @@ -602,9 +647,9 @@ module ActiveRecord 
     | 
|
| 
       602 
647 
     | 
    
         
             
                          contained += "_"
         
     | 
| 
       603 
648 
     | 
    
         
             
                        end
         
     | 
| 
       604 
649 
     | 
    
         | 
| 
       605 
     | 
    
         
            -
                        "#{full_table_name_prefix}#{contained}#{undecorated_table_name( 
     | 
| 
      
 650 
     | 
    
         
            +
                        "#{full_table_name_prefix}#{contained}#{undecorated_table_name(model_name)}#{full_table_name_suffix}"
         
     | 
| 
       606 
651 
     | 
    
         
             
                      else
         
     | 
| 
       607 
     | 
    
         
            -
                        # STI subclasses always use their superclass' table.
         
     | 
| 
      
 652 
     | 
    
         
            +
                        # STI subclasses always use their superclass's table.
         
     | 
| 
       608 
653 
     | 
    
         
             
                        base_class.table_name
         
     | 
| 
       609 
654 
     | 
    
         
             
                      end
         
     | 
| 
       610 
655 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -616,32 +661,6 @@ module ActiveRecord 
     | 
|
| 
       616 
661 
     | 
    
         
             
                        type
         
     | 
| 
       617 
662 
     | 
    
         
             
                      end
         
     | 
| 
       618 
663 
     | 
    
         
             
                    end
         
     | 
| 
       619 
     | 
    
         
            -
             
     | 
| 
       620 
     | 
    
         
            -
                    def warn_if_deprecated_type(column)
         
     | 
| 
       621 
     | 
    
         
            -
                      return if attributes_to_define_after_schema_loads.key?(column.name)
         
     | 
| 
       622 
     | 
    
         
            -
                      return unless column.respond_to?(:oid)
         
     | 
| 
       623 
     | 
    
         
            -
             
     | 
| 
       624 
     | 
    
         
            -
                      if column.array?
         
     | 
| 
       625 
     | 
    
         
            -
                        array_arguments = ", array: true"
         
     | 
| 
       626 
     | 
    
         
            -
                      else
         
     | 
| 
       627 
     | 
    
         
            -
                        array_arguments = ""
         
     | 
| 
       628 
     | 
    
         
            -
                      end
         
     | 
| 
       629 
     | 
    
         
            -
             
     | 
| 
       630 
     | 
    
         
            -
                      if column.sql_type.start_with?("interval")
         
     | 
| 
       631 
     | 
    
         
            -
                        precision_arguments = column.precision.presence && ", precision: #{column.precision}"
         
     | 
| 
       632 
     | 
    
         
            -
                        ActiveSupport::Deprecation.warn(<<~WARNING)
         
     | 
| 
       633 
     | 
    
         
            -
                          The behavior of the `:interval` type will be changing in Rails 7.0
         
     | 
| 
       634 
     | 
    
         
            -
                          to return an `ActiveSupport::Duration` object. If you'd like to keep
         
     | 
| 
       635 
     | 
    
         
            -
                          the old behavior, you can add this line to #{self.name} model:
         
     | 
| 
       636 
     | 
    
         
            -
             
     | 
| 
       637 
     | 
    
         
            -
                            attribute :#{column.name}, :string#{precision_arguments}#{array_arguments}
         
     | 
| 
       638 
     | 
    
         
            -
             
     | 
| 
       639 
     | 
    
         
            -
                          If you'd like the new behavior today, you can add this line:
         
     | 
| 
       640 
     | 
    
         
            -
             
     | 
| 
       641 
     | 
    
         
            -
                            attribute :#{column.name}, :interval#{precision_arguments}#{array_arguments}
         
     | 
| 
       642 
     | 
    
         
            -
                        WARNING
         
     | 
| 
       643 
     | 
    
         
            -
                      end
         
     | 
| 
       644 
     | 
    
         
            -
                    end
         
     | 
| 
       645 
664 
     | 
    
         
             
                end
         
     | 
| 
       646 
665 
     | 
    
         
             
              end
         
     | 
| 
       647 
666 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,7 +5,7 @@ require "active_support/core_ext/module/redefine_method" 
     | 
|
| 
       5 
5 
     | 
    
         
             
            require "active_support/core_ext/hash/indifferent_access"
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            module ActiveRecord
         
     | 
| 
       8 
     | 
    
         
            -
              module NestedAttributes  
     | 
| 
      
 8 
     | 
    
         
            +
              module NestedAttributes # :nodoc:
         
     | 
| 
       9 
9 
     | 
    
         
             
                class TooManyRecords < ActiveRecordError
         
     | 
| 
       10 
10 
     | 
    
         
             
                end
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
         @@ -15,7 +15,7 @@ module ActiveRecord 
     | 
|
| 
       15 
15 
     | 
    
         
             
                  class_attribute :nested_attributes_options, instance_writer: false, default: {}
         
     | 
| 
       16 
16 
     | 
    
         
             
                end
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                # = Active Record Nested Attributes
         
     | 
| 
      
 18 
     | 
    
         
            +
                # = Active Record Nested \Attributes
         
     | 
| 
       19 
19 
     | 
    
         
             
                #
         
     | 
| 
       20 
20 
     | 
    
         
             
                # Nested attributes allow you to save attributes on associated records
         
     | 
| 
       21 
21 
     | 
    
         
             
                # through the parent. By default nested attribute updating is turned off
         
     | 
| 
         @@ -180,7 +180,7 @@ module ActiveRecord 
     | 
|
| 
       180 
180 
     | 
    
         
             
                #   member.posts.second.title # => '[UPDATED] other post'
         
     | 
| 
       181 
181 
     | 
    
         
             
                #
         
     | 
| 
       182 
182 
     | 
    
         
             
                # However, the above applies if the parent model is being updated as well.
         
     | 
| 
       183 
     | 
    
         
            -
                # For example,  
     | 
| 
      
 183 
     | 
    
         
            +
                # For example, if you wanted to create a +member+ named _joe_ and wanted to
         
     | 
| 
       184 
184 
     | 
    
         
             
                # update the +posts+ at the same time, that would give an
         
     | 
| 
       185 
185 
     | 
    
         
             
                # ActiveRecord::RecordNotFound error.
         
     | 
| 
       186 
186 
     | 
    
         
             
                #
         
     | 
| 
         @@ -245,18 +245,19 @@ module ActiveRecord 
     | 
|
| 
       245 
245 
     | 
    
         
             
                #
         
     | 
| 
       246 
246 
     | 
    
         
             
                # === Validating the presence of a parent model
         
     | 
| 
       247 
247 
     | 
    
         
             
                #
         
     | 
| 
       248 
     | 
    
         
            -
                #  
     | 
| 
       249 
     | 
    
         
            -
                #  
     | 
| 
       250 
     | 
    
         
            -
                #  
     | 
| 
      
 248 
     | 
    
         
            +
                # The +belongs_to+ association validates the presence of the parent model
         
     | 
| 
      
 249 
     | 
    
         
            +
                # by default. You can disable this behavior by specifying <code>optional: true</code>.
         
     | 
| 
      
 250 
     | 
    
         
            +
                # This can be used, for example, when conditionally validating the presence
         
     | 
| 
      
 251 
     | 
    
         
            +
                # of the parent model:
         
     | 
| 
       251 
252 
     | 
    
         
             
                #
         
     | 
| 
       252 
     | 
    
         
            -
                #   class  
     | 
| 
       253 
     | 
    
         
            -
                #     has_many : 
     | 
| 
       254 
     | 
    
         
            -
                #     accepts_nested_attributes_for : 
     | 
| 
      
 253 
     | 
    
         
            +
                #   class Veterinarian < ActiveRecord::Base
         
     | 
| 
      
 254 
     | 
    
         
            +
                #     has_many :patients, inverse_of: :veterinarian
         
     | 
| 
      
 255 
     | 
    
         
            +
                #     accepts_nested_attributes_for :patients
         
     | 
| 
       255 
256 
     | 
    
         
             
                #   end
         
     | 
| 
       256 
257 
     | 
    
         
             
                #
         
     | 
| 
       257 
     | 
    
         
            -
                #   class  
     | 
| 
       258 
     | 
    
         
            -
                #     belongs_to : 
     | 
| 
       259 
     | 
    
         
            -
                #      
     | 
| 
      
 258 
     | 
    
         
            +
                #   class Patient < ActiveRecord::Base
         
     | 
| 
      
 259 
     | 
    
         
            +
                #     belongs_to :veterinarian, inverse_of: :patients, optional: true
         
     | 
| 
      
 260 
     | 
    
         
            +
                #     validates :veterinarian, presence: true, unless: -> { awaiting_intake }
         
     | 
| 
       260 
261 
     | 
    
         
             
                #   end
         
     | 
| 
       261 
262 
     | 
    
         
             
                #
         
     | 
| 
       262 
263 
     | 
    
         
             
                # Note that if you do not specify the +:inverse_of+ option, then
         
     | 
| 
         @@ -279,6 +280,24 @@ module ActiveRecord 
     | 
|
| 
       279 
280 
     | 
    
         
             
                #   member = Member.new
         
     | 
| 
       280 
281 
     | 
    
         
             
                #   member.avatar_attributes = {icon: 'sad'}
         
     | 
| 
       281 
282 
     | 
    
         
             
                #   member.avatar.width # => 200
         
     | 
| 
      
 283 
     | 
    
         
            +
                #
         
     | 
| 
      
 284 
     | 
    
         
            +
                # === Creating forms with nested attributes
         
     | 
| 
      
 285 
     | 
    
         
            +
                #
         
     | 
| 
      
 286 
     | 
    
         
            +
                # Use ActionView::Helpers::FormHelper#fields_for to create form elements for
         
     | 
| 
      
 287 
     | 
    
         
            +
                # nested attributes.
         
     | 
| 
      
 288 
     | 
    
         
            +
                #
         
     | 
| 
      
 289 
     | 
    
         
            +
                # Integration test params should reflect the structure of the form. For
         
     | 
| 
      
 290 
     | 
    
         
            +
                # example:
         
     | 
| 
      
 291 
     | 
    
         
            +
                #
         
     | 
| 
      
 292 
     | 
    
         
            +
                #   post members_path, params: {
         
     | 
| 
      
 293 
     | 
    
         
            +
                #     member: {
         
     | 
| 
      
 294 
     | 
    
         
            +
                #       name: 'joe',
         
     | 
| 
      
 295 
     | 
    
         
            +
                #       posts_attributes: {
         
     | 
| 
      
 296 
     | 
    
         
            +
                #         '0' => { title: 'Foo' },
         
     | 
| 
      
 297 
     | 
    
         
            +
                #         '1' => { title: 'Bar' }
         
     | 
| 
      
 298 
     | 
    
         
            +
                #       }
         
     | 
| 
      
 299 
     | 
    
         
            +
                #     }
         
     | 
| 
      
 300 
     | 
    
         
            +
                #   }
         
     | 
| 
       282 
301 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
       283 
302 
     | 
    
         
             
                  REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == "_destroy" || value.blank? } }
         
     | 
| 
       284 
303 
     | 
    
         | 
| 
         @@ -288,7 +307,7 @@ module ActiveRecord 
     | 
|
| 
       288 
307 
     | 
    
         
             
                  # [:allow_destroy]
         
     | 
| 
       289 
308 
     | 
    
         
             
                  #   If true, destroys any members from the attributes hash with a
         
     | 
| 
       290 
309 
     | 
    
         
             
                  #   <tt>_destroy</tt> key and a value that evaluates to +true+
         
     | 
| 
       291 
     | 
    
         
            -
                  #   (e.g. 1, '1', true, or 'true'). This option is  
     | 
| 
      
 310 
     | 
    
         
            +
                  #   (e.g. 1, '1', true, or 'true'). This option is false by default.
         
     | 
| 
       292 
311 
     | 
    
         
             
                  # [:reject_if]
         
     | 
| 
       293 
312 
     | 
    
         
             
                  #   Allows you to specify a Proc or a Symbol pointing to a method
         
     | 
| 
       294 
313 
     | 
    
         
             
                  #   that checks whether a record should be built for a certain attribute
         
     | 
| 
         @@ -313,11 +332,11 @@ module ActiveRecord 
     | 
|
| 
       313 
332 
     | 
    
         
             
                  #   nested attributes are going to be used when an associated record already
         
     | 
| 
       314 
333 
     | 
    
         
             
                  #   exists. In general, an existing record may either be updated with the
         
     | 
| 
       315 
334 
     | 
    
         
             
                  #   new set of attribute values or be replaced by a wholly new record
         
     | 
| 
       316 
     | 
    
         
            -
                  #   containing those values. By default the +:update_only+ option is  
     | 
| 
      
 335 
     | 
    
         
            +
                  #   containing those values. By default the +:update_only+ option is false
         
     | 
| 
       317 
336 
     | 
    
         
             
                  #   and the nested attributes are used to update the existing record only
         
     | 
| 
       318 
337 
     | 
    
         
             
                  #   if they include the record's <tt>:id</tt> value. Otherwise a new
         
     | 
| 
       319 
338 
     | 
    
         
             
                  #   record will be instantiated and used to replace the existing one.
         
     | 
| 
       320 
     | 
    
         
            -
                  #   However if the +:update_only+ option is  
     | 
| 
      
 339 
     | 
    
         
            +
                  #   However if the +:update_only+ option is true, the nested attributes
         
     | 
| 
       321 
340 
     | 
    
         
             
                  #   are used to update the record's attributes always, regardless of
         
     | 
| 
       322 
341 
     | 
    
         
             
                  #   whether the <tt>:id</tt> is present. The option is ignored for collection
         
     | 
| 
       323 
342 
     | 
    
         
             
                  #   associations.
         
     | 
| 
         @@ -374,11 +393,11 @@ module ActiveRecord 
     | 
|
| 
       374 
393 
     | 
    
         
             
                    end
         
     | 
| 
       375 
394 
     | 
    
         
             
                end
         
     | 
| 
       376 
395 
     | 
    
         | 
| 
       377 
     | 
    
         
            -
                # Returns ActiveRecord::AutosaveAssociation 
     | 
| 
      
 396 
     | 
    
         
            +
                # Returns ActiveRecord::AutosaveAssociation#marked_for_destruction? It's
         
     | 
| 
       378 
397 
     | 
    
         
             
                # used in conjunction with fields_for to build a form element for the
         
     | 
| 
       379 
398 
     | 
    
         
             
                # destruction of this association.
         
     | 
| 
       380 
399 
     | 
    
         
             
                #
         
     | 
| 
       381 
     | 
    
         
            -
                # See ActionView::Helpers::FormHelper 
     | 
| 
      
 400 
     | 
    
         
            +
                # See ActionView::Helpers::FormHelper#fields_for for more info.
         
     | 
| 
       382 
401 
     | 
    
         
             
                def _destroy
         
     | 
| 
       383 
402 
     | 
    
         
             
                  marked_for_destruction?
         
     | 
| 
       384 
403 
     | 
    
         
             
                end
         
     | 
| 
         @@ -486,7 +505,7 @@ module ActiveRecord 
     | 
|
| 
       486 
505 
     | 
    
         
             
                    existing_records = if association.loaded?
         
     | 
| 
       487 
506 
     | 
    
         
             
                      association.target
         
     | 
| 
       488 
507 
     | 
    
         
             
                    else
         
     | 
| 
       489 
     | 
    
         
            -
                      attribute_ids = attributes_collection. 
     | 
| 
      
 508 
     | 
    
         
            +
                      attribute_ids = attributes_collection.filter_map { |a| a["id"] || a[:id] }
         
     | 
| 
       490 
509 
     | 
    
         
             
                      attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
         
     | 
| 
       491 
510 
     | 
    
         
             
                    end
         
     | 
| 
       492 
511 
     | 
    
         | 
| 
         @@ -26,20 +26,20 @@ module ActiveRecord 
     | 
|
| 
       26 
26 
     | 
    
         
             
                end
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
                class << self
         
     | 
| 
       29 
     | 
    
         
            -
                  def apply_to(klass)  
     | 
| 
      
 29 
     | 
    
         
            +
                  def apply_to(klass) # :nodoc:
         
     | 
| 
       30 
30 
     | 
    
         
             
                    klasses.push(klass)
         
     | 
| 
       31 
31 
     | 
    
         
             
                    yield
         
     | 
| 
       32 
32 
     | 
    
         
             
                  ensure
         
     | 
| 
       33 
33 
     | 
    
         
             
                    klasses.pop
         
     | 
| 
       34 
34 
     | 
    
         
             
                  end
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
                  def applied_to?(klass)  
     | 
| 
      
 36 
     | 
    
         
            +
                  def applied_to?(klass) # :nodoc:
         
     | 
| 
       37 
37 
     | 
    
         
             
                    klasses.any? { |k| k >= klass }
         
     | 
| 
       38 
38 
     | 
    
         
             
                  end
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
40 
     | 
    
         
             
                  private
         
     | 
| 
       41 
41 
     | 
    
         
             
                    def klasses
         
     | 
| 
       42 
     | 
    
         
            -
                       
     | 
| 
      
 42 
     | 
    
         
            +
                      ActiveSupport::IsolatedExecutionState[:active_record_no_touching_classes] ||= []
         
     | 
| 
       43 
43 
     | 
    
         
             
                    end
         
     | 
| 
       44 
44 
     | 
    
         
             
                end
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
         @@ -0,0 +1,167 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActiveRecord # :nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Normalization
         
     | 
| 
      
 5 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                included do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  class_attribute :normalized_attributes, default: Set.new
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  before_validation :normalize_changed_in_place_attributes
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                # Normalizes a specified attribute using its declared normalizations.
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                # ==== Examples
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                #   class User < ActiveRecord::Base
         
     | 
| 
      
 18 
     | 
    
         
            +
                #     normalizes :email, with: -> email { email.strip.downcase }
         
     | 
| 
      
 19 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 20 
     | 
    
         
            +
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                #   legacy_user = User.find(1)
         
     | 
| 
      
 22 
     | 
    
         
            +
                #   legacy_user.email # => " CRUISE-CONTROL@EXAMPLE.COM\n"
         
     | 
| 
      
 23 
     | 
    
         
            +
                #   legacy_user.normalize_attribute(:email)
         
     | 
| 
      
 24 
     | 
    
         
            +
                #   legacy_user.email # => "cruise-control@example.com"
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   legacy_user.save
         
     | 
| 
      
 26 
     | 
    
         
            +
                def normalize_attribute(name)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # Treat the value as a new, unnormalized value.
         
     | 
| 
      
 28 
     | 
    
         
            +
                  self[name] = self[name]
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # Declares a normalization for one or more attributes. The normalization
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # is applied when the attribute is assigned or updated, and the normalized
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # value will be persisted to the database. The normalization is also
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # applied to the corresponding keyword argument of query methods. This
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # allows a record to be created and later queried using unnormalized
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # values.
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # However, to prevent confusion, the normalization will not be applied
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # when the attribute is fetched from the database. This means that if a
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # record was persisted before the normalization was declared, the record's
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # attribute will not be normalized until either it is assigned a new
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # value, or it is explicitly migrated via Normalization#normalize_attribute.
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # Because the normalization may be applied multiple times, it should be
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # _idempotent_. In other words, applying the normalization more than once
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # should have the same result as applying it only once.
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # By default, the normalization will not be applied to +nil+ values. This
         
     | 
| 
      
 50 
     | 
    
         
            +
                  # behavior can be changed with the +:apply_to_nil+ option.
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # Be aware that if your app was created before Rails 7.1, and your app
         
     | 
| 
      
 53 
     | 
    
         
            +
                  # marshals instances of the targeted model (for example, when caching),
         
     | 
| 
      
 54 
     | 
    
         
            +
                  # then you should set ActiveRecord.marshalling_format_version to +7.1+ or
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # higher via either <tt>config.load_defaults 7.1</tt> or
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # <tt>config.active_record.marshalling_format_version = 7.1</tt>.
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # Otherwise, +Marshal+ may attempt to serialize the normalization +Proc+
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # and raise +TypeError+.
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # ==== Options
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # * +:with+ - Any callable object that accepts the attribute's value as
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #   its sole argument, and returns it normalized.
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # * +:apply_to_nil+ - Whether to apply the normalization to +nil+ values.
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #   Defaults to +false+.
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #
         
     | 
| 
      
 67 
     | 
    
         
            +
                  # ==== Examples
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #   class User < ActiveRecord::Base
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #     normalizes :email, with: -> email { email.strip.downcase }
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #     normalizes :phone, with: -> phone { phone.delete("^0-9").delete_prefix("1") }
         
     | 
| 
      
 72 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #
         
     | 
| 
      
 74 
     | 
    
         
            +
                  #   user = User.create(email: " CRUISE-CONTROL@EXAMPLE.COM\n")
         
     | 
| 
      
 75 
     | 
    
         
            +
                  #   user.email                  # => "cruise-control@example.com"
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #
         
     | 
| 
      
 77 
     | 
    
         
            +
                  #   user = User.find_by(email: "\tCRUISE-CONTROL@EXAMPLE.COM ")
         
     | 
| 
      
 78 
     | 
    
         
            +
                  #   user.email                  # => "cruise-control@example.com"
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #   user.email_before_type_cast # => "cruise-control@example.com"
         
     | 
| 
      
 80 
     | 
    
         
            +
                  #
         
     | 
| 
      
 81 
     | 
    
         
            +
                  #   User.where(email: "\tCRUISE-CONTROL@EXAMPLE.COM ").count         # => 1
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #   User.where(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]).count # => 0
         
     | 
| 
      
 83 
     | 
    
         
            +
                  #
         
     | 
| 
      
 84 
     | 
    
         
            +
                  #   User.exists?(email: "\tCRUISE-CONTROL@EXAMPLE.COM ")         # => true
         
     | 
| 
      
 85 
     | 
    
         
            +
                  #   User.exists?(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]) # => false
         
     | 
| 
      
 86 
     | 
    
         
            +
                  #
         
     | 
| 
      
 87 
     | 
    
         
            +
                  #   User.normalize_value_for(:phone, "+1 (555) 867-5309") # => "5558675309"
         
     | 
| 
      
 88 
     | 
    
         
            +
                  def normalizes(*names, with:, apply_to_nil: false)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    names.each do |name|
         
     | 
| 
      
 90 
     | 
    
         
            +
                      attribute(name) do |cast_type|
         
     | 
| 
      
 91 
     | 
    
         
            +
                        NormalizedValueType.new(cast_type: cast_type, normalizer: with, normalize_nil: apply_to_nil)
         
     | 
| 
      
 92 
     | 
    
         
            +
                      end
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                    self.normalized_attributes += names.map(&:to_sym)
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  # Normalizes a given +value+ using normalizations declared for +name+.
         
     | 
| 
      
 99 
     | 
    
         
            +
                  #
         
     | 
| 
      
 100 
     | 
    
         
            +
                  # ==== Examples
         
     | 
| 
      
 101 
     | 
    
         
            +
                  #
         
     | 
| 
      
 102 
     | 
    
         
            +
                  #   class User < ActiveRecord::Base
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #     normalizes :email, with: -> email { email.strip.downcase }
         
     | 
| 
      
 104 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 105 
     | 
    
         
            +
                  #
         
     | 
| 
      
 106 
     | 
    
         
            +
                  #   User.normalize_value_for(:email, " CRUISE-CONTROL@EXAMPLE.COM\n")
         
     | 
| 
      
 107 
     | 
    
         
            +
                  #   # => "cruise-control@example.com"
         
     | 
| 
      
 108 
     | 
    
         
            +
                  def normalize_value_for(name, value)
         
     | 
| 
      
 109 
     | 
    
         
            +
                    type_for_attribute(name).cast(value)
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                private
         
     | 
| 
      
 114 
     | 
    
         
            +
                  def normalize_changed_in_place_attributes
         
     | 
| 
      
 115 
     | 
    
         
            +
                    self.class.normalized_attributes.each do |name|
         
     | 
| 
      
 116 
     | 
    
         
            +
                      normalize_attribute(name) if attribute_changed_in_place?(name)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    end
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                  class NormalizedValueType < DelegateClass(ActiveModel::Type::Value) # :nodoc:
         
     | 
| 
      
 121 
     | 
    
         
            +
                    include ActiveModel::Type::SerializeCastValue
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                    attr_reader :cast_type, :normalizer, :normalize_nil
         
     | 
| 
      
 124 
     | 
    
         
            +
                    alias :normalize_nil? :normalize_nil
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                    def initialize(cast_type:, normalizer:, normalize_nil:)
         
     | 
| 
      
 127 
     | 
    
         
            +
                      @cast_type = cast_type
         
     | 
| 
      
 128 
     | 
    
         
            +
                      @normalizer = normalizer
         
     | 
| 
      
 129 
     | 
    
         
            +
                      @normalize_nil = normalize_nil
         
     | 
| 
      
 130 
     | 
    
         
            +
                      super(cast_type)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                    def cast(value)
         
     | 
| 
      
 134 
     | 
    
         
            +
                      normalize(super(value))
         
     | 
| 
      
 135 
     | 
    
         
            +
                    end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                    def serialize(value)
         
     | 
| 
      
 138 
     | 
    
         
            +
                      serialize_cast_value(cast(value))
         
     | 
| 
      
 139 
     | 
    
         
            +
                    end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                    def serialize_cast_value(value)
         
     | 
| 
      
 142 
     | 
    
         
            +
                      ActiveModel::Type::SerializeCastValue.serialize(cast_type, value)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                    def ==(other)
         
     | 
| 
      
 146 
     | 
    
         
            +
                      self.class == other.class &&
         
     | 
| 
      
 147 
     | 
    
         
            +
                        normalize_nil? == other.normalize_nil? &&
         
     | 
| 
      
 148 
     | 
    
         
            +
                        normalizer == other.normalizer &&
         
     | 
| 
      
 149 
     | 
    
         
            +
                        cast_type == other.cast_type
         
     | 
| 
      
 150 
     | 
    
         
            +
                    end
         
     | 
| 
      
 151 
     | 
    
         
            +
                    alias eql? ==
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                    def hash
         
     | 
| 
      
 154 
     | 
    
         
            +
                      [self.class, cast_type, normalizer, normalize_nil?].hash
         
     | 
| 
      
 155 
     | 
    
         
            +
                    end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                    def inspect
         
     | 
| 
      
 158 
     | 
    
         
            +
                      Kernel.instance_method(:inspect).bind_call(self)
         
     | 
| 
      
 159 
     | 
    
         
            +
                    end
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                    private
         
     | 
| 
      
 162 
     | 
    
         
            +
                      def normalize(value)
         
     | 
| 
      
 163 
     | 
    
         
            +
                        normalizer.call(value) unless value.nil? && !normalize_nil?
         
     | 
| 
      
 164 
     | 
    
         
            +
                      end
         
     | 
| 
      
 165 
     | 
    
         
            +
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
              end
         
     | 
| 
      
 167 
     | 
    
         
            +
            end
         
     |