activerecord 6.0.0 → 7.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +996 -594
- data/MIT-LICENSE +1 -1
- data/README.rdoc +34 -34
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +22 -20
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +41 -30
- data/lib/active_record/associations/association.rb +106 -41
- data/lib/active_record/associations/association_scope.rb +30 -21
- data/lib/active_record/associations/belongs_to_association.rb +69 -14
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
- data/lib/active_record/associations/builder/association.rb +39 -6
- data/lib/active_record/associations/builder/belongs_to.rb +47 -17
- data/lib/active_record/associations/builder/collection_association.rb +14 -6
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
- data/lib/active_record/associations/builder/has_many.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +13 -16
- data/lib/active_record/associations/builder/singular_association.rb +7 -3
- data/lib/active_record/associations/collection_association.rb +90 -53
- data/lib/active_record/associations/collection_proxy.rb +54 -19
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +21 -1
- data/lib/active_record/associations/has_many_association.rb +41 -10
- data/lib/active_record/associations/has_many_through_association.rb +29 -12
- data/lib/active_record/associations/has_one_association.rb +33 -9
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +97 -54
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +237 -54
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +51 -17
- data/lib/active_record/associations/preloader.rb +55 -121
- data/lib/active_record/associations/singular_association.rb +16 -4
- data/lib/active_record/associations/through_association.rb +26 -15
- data/lib/active_record/associations.rb +454 -440
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +11 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +75 -34
- data/lib/active_record/attribute_methods/primary_key.rb +53 -31
- data/lib/active_record/attribute_methods/query.rb +31 -22
- data/lib/active_record/attribute_methods/read.rb +16 -17
- data/lib/active_record/attribute_methods/serialization.rb +177 -35
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
- data/lib/active_record/attribute_methods/write.rb +16 -28
- data/lib/active_record/attribute_methods.rb +227 -100
- data/lib/active_record/attributes.rb +94 -56
- data/lib/active_record/autosave_association.rb +119 -73
- data/lib/active_record/base.rb +31 -21
- data/lib/active_record/callbacks.rb +168 -55
- 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 -25
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
- data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
- data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
- data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
- data/lib/active_record/connection_adapters/column.rb +28 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
- data/lib/active_record/connection_adapters/pool_config.rb +83 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
- data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +176 -0
- data/lib/active_record/connection_handling.rb +243 -115
- data/lib/active_record/core.rb +481 -199
- data/lib/active_record/counter_cache.rb +69 -32
- data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
- data/lib/active_record/database_configurations/database_config.rb +77 -10
- data/lib/active_record/database_configurations/hash_config.rb +148 -26
- data/lib/active_record/database_configurations/url_config.rb +44 -45
- data/lib/active_record/database_configurations.rb +190 -114
- data/lib/active_record/delegated_type.rb +279 -0
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +38 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +5 -6
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +171 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +224 -73
- data/lib/active_record/errors.rb +254 -36
- data/lib/active_record/explain.rb +30 -17
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +22 -15
- data/lib/active_record/fixture_set/model_metadata.rb +15 -6
- data/lib/active_record/fixture_set/render_context.rb +3 -1
- data/lib/active_record/fixture_set/table_row.rb +88 -16
- data/lib/active_record/fixture_set/table_rows.rb +4 -5
- data/lib/active_record/fixtures.rb +229 -116
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +121 -48
- data/lib/active_record/insert_all.rb +178 -29
- data/lib/active_record/integration.rb +16 -14
- data/lib/active_record/internal_metadata.rb +132 -21
- data/lib/active_record/legacy_yaml_adapter.rb +3 -36
- data/lib/active_record/locking/optimistic.rb +64 -33
- data/lib/active_record/locking/pessimistic.rb +21 -8
- data/lib/active_record/log_subscriber.rb +61 -30
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
- data/lib/active_record/middleware/database_selector.rb +25 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +160 -55
- data/lib/active_record/migration/compatibility.rb +286 -43
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -2
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +421 -193
- data/lib/active_record/model_schema.rb +217 -125
- data/lib/active_record/nested_attributes.rb +62 -27
- data/lib/active_record/no_touching.rb +4 -4
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +322 -319
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -15
- data/lib/active_record/query_logs.rb +193 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +54 -14
- data/lib/active_record/railtie.rb +250 -72
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +312 -197
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +45 -3
- data/lib/active_record/reflection.rb +389 -146
- data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
- data/lib/active_record/relation/batches.rb +214 -73
- data/lib/active_record/relation/calculations.rb +379 -124
- data/lib/active_record/relation/delegation.rb +36 -23
- data/lib/active_record/relation/finder_methods.rb +159 -49
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +41 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +79 -53
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +1156 -279
- data/lib/active_record/relation/record_fetch_warning.rb +12 -11
- data/lib/active_record/relation/spawn_methods.rb +10 -9
- data/lib/active_record/relation/where_clause.rb +100 -66
- data/lib/active_record/relation.rb +829 -194
- data/lib/active_record/result.rb +76 -56
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +86 -47
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +140 -33
- data/lib/active_record/schema_migration.rb +74 -29
- data/lib/active_record/scoping/default.rb +73 -19
- data/lib/active_record/scoping/named.rb +10 -28
- data/lib/active_record/scoping.rb +65 -35
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +34 -8
- data/lib/active_record/serialization.rb +11 -4
- data/lib/active_record/signed_id.rb +138 -0
- data/lib/active_record/statement_cache.rb +26 -10
- data/lib/active_record/store.rb +19 -14
- data/lib/active_record/suppressor.rb +15 -17
- data/lib/active_record/table_metadata.rb +46 -36
- data/lib/active_record/tasks/database_tasks.rb +371 -205
- data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +189 -104
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +35 -25
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +31 -27
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +131 -99
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +33 -18
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +11 -6
- data/lib/active_record/type/time.rb +14 -0
- data/lib/active_record/type/type_map.rb +17 -21
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +7 -2
- data/lib/active_record/type_caster/connection.rb +4 -5
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -8
- data/lib/active_record/validations/numericality.rb +36 -0
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +88 -18
- data/lib/active_record/validations.rb +15 -8
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +446 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +4 -8
- data/lib/arel/collectors/bind.rb +8 -1
- data/lib/arel/collectors/composite.rb +15 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/crud.rb +30 -22
- data/lib/arel/delete_manager.rb +23 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +82 -9
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +22 -10
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +14 -13
- data/lib/arel/nodes/equality.rb +6 -9
- 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/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +68 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +122 -11
- data/lib/arel/nodes/ordering.rb +27 -0
- 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 +16 -0
- data/lib/arel/nodes/table_alias.rb +11 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes/update_statement.rb +11 -4
- data/lib/arel/nodes.rb +10 -3
- data/lib/arel/predications.rb +31 -28
- data/lib/arel/select_manager.rb +18 -9
- data/lib/arel/table.rb +21 -10
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +25 -5
- data/lib/arel/visitors/dot.rb +94 -90
- data/lib/arel/visitors/mysql.rb +34 -6
- data/lib/arel/visitors/postgresql.rb +5 -16
- data/lib/arel/visitors/sqlite.rb +25 -1
- data/lib/arel/visitors/to_sql.rb +227 -81
- data/lib/arel/visitors/visitor.rb +2 -3
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +37 -15
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +9 -3
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- 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 +117 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/null_relation.rb +0 -68
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require "active_support/core_ext/hash/except"
|
|
4
4
|
require "active_support/core_ext/module/redefine_method"
|
|
5
|
-
require "active_support/core_ext/object/try"
|
|
6
5
|
require "active_support/core_ext/hash/indifferent_access"
|
|
7
6
|
|
|
8
7
|
module ActiveRecord
|
|
9
|
-
module NestedAttributes
|
|
8
|
+
module NestedAttributes # :nodoc:
|
|
10
9
|
class TooManyRecords < ActiveRecordError
|
|
11
10
|
end
|
|
12
11
|
|
|
@@ -16,7 +15,7 @@ module ActiveRecord
|
|
|
16
15
|
class_attribute :nested_attributes_options, instance_writer: false, default: {}
|
|
17
16
|
end
|
|
18
17
|
|
|
19
|
-
# = Active Record Nested Attributes
|
|
18
|
+
# = Active Record Nested \Attributes
|
|
20
19
|
#
|
|
21
20
|
# Nested attributes allow you to save attributes on associated records
|
|
22
21
|
# through the parent. By default nested attribute updating is turned off
|
|
@@ -181,7 +180,7 @@ module ActiveRecord
|
|
|
181
180
|
# member.posts.second.title # => '[UPDATED] other post'
|
|
182
181
|
#
|
|
183
182
|
# However, the above applies if the parent model is being updated as well.
|
|
184
|
-
# For example,
|
|
183
|
+
# For example, if you wanted to create a +member+ named _joe_ and wanted to
|
|
185
184
|
# update the +posts+ at the same time, that would give an
|
|
186
185
|
# ActiveRecord::RecordNotFound error.
|
|
187
186
|
#
|
|
@@ -246,18 +245,19 @@ module ActiveRecord
|
|
|
246
245
|
#
|
|
247
246
|
# === Validating the presence of a parent model
|
|
248
247
|
#
|
|
249
|
-
#
|
|
250
|
-
#
|
|
251
|
-
#
|
|
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:
|
|
252
252
|
#
|
|
253
|
-
# class
|
|
254
|
-
# has_many :
|
|
255
|
-
# accepts_nested_attributes_for :
|
|
253
|
+
# class Veterinarian < ActiveRecord::Base
|
|
254
|
+
# has_many :patients, inverse_of: :veterinarian
|
|
255
|
+
# accepts_nested_attributes_for :patients
|
|
256
256
|
# end
|
|
257
257
|
#
|
|
258
|
-
# class
|
|
259
|
-
# belongs_to :
|
|
260
|
-
#
|
|
258
|
+
# class Patient < ActiveRecord::Base
|
|
259
|
+
# belongs_to :veterinarian, inverse_of: :patients, optional: true
|
|
260
|
+
# validates :veterinarian, presence: true, unless: -> { awaiting_intake }
|
|
261
261
|
# end
|
|
262
262
|
#
|
|
263
263
|
# Note that if you do not specify the +:inverse_of+ option, then
|
|
@@ -280,6 +280,24 @@ module ActiveRecord
|
|
|
280
280
|
# member = Member.new
|
|
281
281
|
# member.avatar_attributes = {icon: 'sad'}
|
|
282
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
|
+
# }
|
|
283
301
|
module ClassMethods
|
|
284
302
|
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == "_destroy" || value.blank? } }
|
|
285
303
|
|
|
@@ -289,7 +307,7 @@ module ActiveRecord
|
|
|
289
307
|
# [:allow_destroy]
|
|
290
308
|
# If true, destroys any members from the attributes hash with a
|
|
291
309
|
# <tt>_destroy</tt> key and a value that evaluates to +true+
|
|
292
|
-
# (
|
|
310
|
+
# (e.g. 1, '1', true, or 'true'). This option is false by default.
|
|
293
311
|
# [:reject_if]
|
|
294
312
|
# Allows you to specify a Proc or a Symbol pointing to a method
|
|
295
313
|
# that checks whether a record should be built for a certain attribute
|
|
@@ -314,11 +332,11 @@ module ActiveRecord
|
|
|
314
332
|
# nested attributes are going to be used when an associated record already
|
|
315
333
|
# exists. In general, an existing record may either be updated with the
|
|
316
334
|
# new set of attribute values or be replaced by a wholly new record
|
|
317
|
-
# containing those values. By default the +:update_only+ option is
|
|
335
|
+
# containing those values. By default the +:update_only+ option is false
|
|
318
336
|
# and the nested attributes are used to update the existing record only
|
|
319
337
|
# if they include the record's <tt>:id</tt> value. Otherwise a new
|
|
320
338
|
# record will be instantiated and used to replace the existing one.
|
|
321
|
-
# However if the +:update_only+ option is
|
|
339
|
+
# However if the +:update_only+ option is true, the nested attributes
|
|
322
340
|
# are used to update the record's attributes always, regardless of
|
|
323
341
|
# whether the <tt>:id</tt> is present. The option is ignored for collection
|
|
324
342
|
# associations.
|
|
@@ -354,7 +372,6 @@ module ActiveRecord
|
|
|
354
372
|
end
|
|
355
373
|
|
|
356
374
|
private
|
|
357
|
-
|
|
358
375
|
# Generates a writer method for this association. Serves as a point for
|
|
359
376
|
# accessing the objects in the association. For example, this method
|
|
360
377
|
# could generate the following:
|
|
@@ -376,17 +393,16 @@ module ActiveRecord
|
|
|
376
393
|
end
|
|
377
394
|
end
|
|
378
395
|
|
|
379
|
-
# Returns ActiveRecord::AutosaveAssociation
|
|
396
|
+
# Returns ActiveRecord::AutosaveAssociation#marked_for_destruction? It's
|
|
380
397
|
# used in conjunction with fields_for to build a form element for the
|
|
381
398
|
# destruction of this association.
|
|
382
399
|
#
|
|
383
|
-
# See ActionView::Helpers::FormHelper
|
|
400
|
+
# See ActionView::Helpers::FormHelper#fields_for for more info.
|
|
384
401
|
def _destroy
|
|
385
402
|
marked_for_destruction?
|
|
386
403
|
end
|
|
387
404
|
|
|
388
405
|
private
|
|
389
|
-
|
|
390
406
|
# Attribute hash keys that should not be assigned as normal attributes.
|
|
391
407
|
# These hash keys are nested attributes implementation details.
|
|
392
408
|
UNASSIGNABLE_KEYS = %w( id _destroy )
|
|
@@ -405,10 +421,15 @@ module ActiveRecord
|
|
|
405
421
|
# update_only is true, and a <tt>:_destroy</tt> key set to a truthy value,
|
|
406
422
|
# then the existing record will be marked for destruction.
|
|
407
423
|
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
|
408
|
-
options = nested_attributes_options[association_name]
|
|
409
424
|
if attributes.respond_to?(:permitted?)
|
|
410
425
|
attributes = attributes.to_h
|
|
411
426
|
end
|
|
427
|
+
|
|
428
|
+
unless attributes.is_a?(Hash)
|
|
429
|
+
raise ArgumentError, "Hash expected for `#{association_name}` attributes, got #{attributes.class.name}"
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
options = nested_attributes_options[association_name]
|
|
412
433
|
attributes = attributes.with_indifferent_access
|
|
413
434
|
existing_record = send(association_name)
|
|
414
435
|
|
|
@@ -470,7 +491,7 @@ module ActiveRecord
|
|
|
470
491
|
end
|
|
471
492
|
|
|
472
493
|
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
|
|
473
|
-
raise ArgumentError, "Hash or Array expected for
|
|
494
|
+
raise ArgumentError, "Hash or Array expected for `#{association_name}` attributes, got #{attributes_collection.class.name}"
|
|
474
495
|
end
|
|
475
496
|
|
|
476
497
|
check_record_limit!(options[:limit], attributes_collection)
|
|
@@ -489,11 +510,11 @@ module ActiveRecord
|
|
|
489
510
|
existing_records = if association.loaded?
|
|
490
511
|
association.target
|
|
491
512
|
else
|
|
492
|
-
attribute_ids = attributes_collection.
|
|
513
|
+
attribute_ids = attributes_collection.filter_map { |a| a["id"] || a[:id] }
|
|
493
514
|
attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
|
|
494
515
|
end
|
|
495
516
|
|
|
496
|
-
attributes_collection.
|
|
517
|
+
records = attributes_collection.map do |attributes|
|
|
497
518
|
if attributes.respond_to?(:permitted?)
|
|
498
519
|
attributes = attributes.to_h
|
|
499
520
|
end
|
|
@@ -503,24 +524,27 @@ module ActiveRecord
|
|
|
503
524
|
unless reject_new_record?(association_name, attributes)
|
|
504
525
|
association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
|
|
505
526
|
end
|
|
506
|
-
elsif existing_record = existing_records
|
|
527
|
+
elsif existing_record = find_record_by_id(existing_records, attributes["id"])
|
|
507
528
|
unless call_reject_if(association_name, attributes)
|
|
508
529
|
# Make sure we are operating on the actual object which is in the association's
|
|
509
530
|
# proxy_target array (either by finding it, or adding it if not found)
|
|
510
531
|
# Take into account that the proxy_target may have changed due to callbacks
|
|
511
|
-
target_record = association.target
|
|
532
|
+
target_record = find_record_by_id(association.target, attributes["id"])
|
|
512
533
|
if target_record
|
|
513
534
|
existing_record = target_record
|
|
514
535
|
else
|
|
515
|
-
association.add_to_target(existing_record, :
|
|
536
|
+
association.add_to_target(existing_record, skip_callbacks: true)
|
|
516
537
|
end
|
|
517
538
|
|
|
518
539
|
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
|
540
|
+
existing_record
|
|
519
541
|
end
|
|
520
542
|
else
|
|
521
543
|
raise_nested_attributes_record_not_found!(association_name, attributes["id"])
|
|
522
544
|
end
|
|
523
545
|
end
|
|
546
|
+
|
|
547
|
+
association.nested_attributes_target = records
|
|
524
548
|
end
|
|
525
549
|
|
|
526
550
|
# Takes in a limit and checks if the attributes_collection has too many
|
|
@@ -596,5 +620,16 @@ module ActiveRecord
|
|
|
596
620
|
raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
|
|
597
621
|
model, "id", record_id)
|
|
598
622
|
end
|
|
623
|
+
|
|
624
|
+
def find_record_by_id(records, id)
|
|
625
|
+
return if records.empty?
|
|
626
|
+
|
|
627
|
+
if records.first.class.composite_primary_key?
|
|
628
|
+
id = Array(id).map(&:to_s)
|
|
629
|
+
records.find { |record| Array(record.id).map(&:to_s) == id }
|
|
630
|
+
else
|
|
631
|
+
records.find { |record| record.id.to_s == id.to_s }
|
|
632
|
+
end
|
|
633
|
+
end
|
|
599
634
|
end
|
|
600
635
|
end
|
|
@@ -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
|
|
|
@@ -58,7 +58,7 @@ module ActiveRecord
|
|
|
58
58
|
super unless no_touching?
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
def touch(
|
|
61
|
+
def touch(*, **) # :nodoc:
|
|
62
62
|
super unless no_touching?
|
|
63
63
|
end
|
|
64
64
|
end
|
|
@@ -0,0 +1,163 @@
|
|
|
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
|
+
decorate_attributes(names) do |name, cast_type|
|
|
90
|
+
NormalizedValueType.new(cast_type: cast_type, normalizer: with, normalize_nil: apply_to_nil)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
self.normalized_attributes += names.map(&:to_sym)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Normalizes a given +value+ using normalizations declared for +name+.
|
|
97
|
+
#
|
|
98
|
+
# ==== Examples
|
|
99
|
+
#
|
|
100
|
+
# class User < ActiveRecord::Base
|
|
101
|
+
# normalizes :email, with: -> email { email.strip.downcase }
|
|
102
|
+
# end
|
|
103
|
+
#
|
|
104
|
+
# User.normalize_value_for(:email, " CRUISE-CONTROL@EXAMPLE.COM\n")
|
|
105
|
+
# # => "cruise-control@example.com"
|
|
106
|
+
def normalize_value_for(name, value)
|
|
107
|
+
type_for_attribute(name).cast(value)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
def normalize_changed_in_place_attributes
|
|
113
|
+
self.class.normalized_attributes.each do |name|
|
|
114
|
+
normalize_attribute(name) if attribute_changed_in_place?(name)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
class NormalizedValueType < DelegateClass(ActiveModel::Type::Value) # :nodoc:
|
|
119
|
+
include ActiveModel::Type::SerializeCastValue
|
|
120
|
+
|
|
121
|
+
attr_reader :cast_type, :normalizer, :normalize_nil
|
|
122
|
+
alias :normalize_nil? :normalize_nil
|
|
123
|
+
|
|
124
|
+
def initialize(cast_type:, normalizer:, normalize_nil:)
|
|
125
|
+
@cast_type = cast_type
|
|
126
|
+
@normalizer = normalizer
|
|
127
|
+
@normalize_nil = normalize_nil
|
|
128
|
+
super(cast_type)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def cast(value)
|
|
132
|
+
normalize(super(value))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def serialize(value)
|
|
136
|
+
serialize_cast_value(cast(value))
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def serialize_cast_value(value)
|
|
140
|
+
ActiveModel::Type::SerializeCastValue.serialize(cast_type, value)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def ==(other)
|
|
144
|
+
self.class == other.class &&
|
|
145
|
+
normalize_nil? == other.normalize_nil? &&
|
|
146
|
+
normalizer == other.normalizer &&
|
|
147
|
+
cast_type == other.cast_type
|
|
148
|
+
end
|
|
149
|
+
alias eql? ==
|
|
150
|
+
|
|
151
|
+
def hash
|
|
152
|
+
[self.class, cast_type, normalizer, normalize_nil?].hash
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
define_method(:inspect, Kernel.instance_method(:inspect))
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
def normalize(value)
|
|
159
|
+
normalizer.call(value) unless value.nil? && !normalize_nil?
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|