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
|
@@ -5,56 +5,52 @@ require "concurrent/map"
|
|
|
5
5
|
module ActiveRecord
|
|
6
6
|
module Type
|
|
7
7
|
class TypeMap # :nodoc:
|
|
8
|
-
def initialize
|
|
8
|
+
def initialize(parent = nil)
|
|
9
9
|
@mapping = {}
|
|
10
|
-
@
|
|
11
|
-
|
|
12
|
-
end
|
|
10
|
+
@parent = parent
|
|
11
|
+
@cache = Concurrent::Map.new
|
|
13
12
|
end
|
|
14
13
|
|
|
15
|
-
def lookup(lookup_key
|
|
16
|
-
fetch(lookup_key
|
|
14
|
+
def lookup(lookup_key)
|
|
15
|
+
fetch(lookup_key) { Type.default_value }
|
|
17
16
|
end
|
|
18
17
|
|
|
19
|
-
def fetch(lookup_key,
|
|
20
|
-
@cache
|
|
21
|
-
perform_fetch(lookup_key,
|
|
18
|
+
def fetch(lookup_key, &block)
|
|
19
|
+
@cache.fetch_or_store(lookup_key) do
|
|
20
|
+
perform_fetch(lookup_key, &block)
|
|
22
21
|
end
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
def register_type(key, value = nil, &block)
|
|
26
25
|
raise ::ArgumentError unless value || block
|
|
27
|
-
@cache.clear
|
|
28
26
|
|
|
29
27
|
if block
|
|
30
28
|
@mapping[key] = block
|
|
31
29
|
else
|
|
32
30
|
@mapping[key] = proc { value }
|
|
33
31
|
end
|
|
32
|
+
@cache.clear
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
def alias_type(key, target_key)
|
|
37
|
-
register_type(key) do |sql_type
|
|
36
|
+
register_type(key) do |sql_type|
|
|
38
37
|
metadata = sql_type[/\(.*\)/, 0]
|
|
39
|
-
lookup("#{target_key}#{metadata}"
|
|
38
|
+
lookup("#{target_key}#{metadata}")
|
|
40
39
|
end
|
|
41
40
|
end
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
private
|
|
48
|
-
|
|
49
|
-
def perform_fetch(lookup_key, *args)
|
|
42
|
+
protected
|
|
43
|
+
def perform_fetch(lookup_key, &block)
|
|
50
44
|
matching_pair = @mapping.reverse_each.detect do |key, _|
|
|
51
45
|
key === lookup_key
|
|
52
46
|
end
|
|
53
47
|
|
|
54
48
|
if matching_pair
|
|
55
|
-
matching_pair.last.call(lookup_key
|
|
49
|
+
matching_pair.last.call(lookup_key)
|
|
50
|
+
elsif @parent
|
|
51
|
+
@parent.perform_fetch(lookup_key, &block)
|
|
56
52
|
else
|
|
57
|
-
yield lookup_key
|
|
53
|
+
yield lookup_key
|
|
58
54
|
end
|
|
59
55
|
end
|
|
60
56
|
end
|
data/lib/active_record/type.rb
CHANGED
|
@@ -46,10 +46,13 @@ module ActiveRecord
|
|
|
46
46
|
@default_value ||= Value.new
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
def adapter_name_from(model) # :nodoc:
|
|
50
|
+
model.connection_db_config.adapter.to_sym
|
|
51
|
+
end
|
|
50
52
|
|
|
53
|
+
private
|
|
51
54
|
def current_adapter_name
|
|
52
|
-
ActiveRecord::Base
|
|
55
|
+
adapter_name_from(ActiveRecord::Base)
|
|
53
56
|
end
|
|
54
57
|
end
|
|
55
58
|
|
|
@@ -59,6 +62,7 @@ module ActiveRecord
|
|
|
59
62
|
Decimal = ActiveModel::Type::Decimal
|
|
60
63
|
Float = ActiveModel::Type::Float
|
|
61
64
|
Integer = ActiveModel::Type::Integer
|
|
65
|
+
ImmutableString = ActiveModel::Type::ImmutableString
|
|
62
66
|
String = ActiveModel::Type::String
|
|
63
67
|
Value = ActiveModel::Type::Value
|
|
64
68
|
|
|
@@ -70,6 +74,7 @@ module ActiveRecord
|
|
|
70
74
|
register(:decimal, Type::Decimal, override: false)
|
|
71
75
|
register(:float, Type::Float, override: false)
|
|
72
76
|
register(:integer, Type::Integer, override: false)
|
|
77
|
+
register(:immutable_string, Type::ImmutableString, override: false)
|
|
73
78
|
register(:json, Type::Json, override: false)
|
|
74
79
|
register(:string, Type::String, override: false)
|
|
75
80
|
register(:text, Type::Text, override: false)
|
|
@@ -9,24 +9,23 @@ module ActiveRecord
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def type_cast_for_database(attr_name, value)
|
|
12
|
-
return value if value.is_a?(Arel::Nodes::BindParam)
|
|
13
12
|
type = type_for_attribute(attr_name)
|
|
14
13
|
type.serialize(value)
|
|
15
14
|
end
|
|
16
15
|
|
|
17
16
|
def type_for_attribute(attr_name)
|
|
18
|
-
schema_cache =
|
|
17
|
+
schema_cache = @klass.schema_cache
|
|
19
18
|
|
|
20
19
|
if schema_cache.data_source_exists?(table_name)
|
|
21
20
|
column = schema_cache.columns_hash(table_name)[attr_name.to_s]
|
|
22
|
-
|
|
21
|
+
if column
|
|
22
|
+
type = @klass.with_connection { |connection| connection.lookup_cast_type_from_column(column) }
|
|
23
|
+
end
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
type || Type.default_value
|
|
26
27
|
end
|
|
27
28
|
|
|
28
|
-
delegate :connection, to: :@klass, private: true
|
|
29
|
-
|
|
30
29
|
private
|
|
31
30
|
attr_reader :table_name
|
|
32
31
|
end
|
|
@@ -3,18 +3,21 @@
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
module TypeCaster
|
|
5
5
|
class Map # :nodoc:
|
|
6
|
-
def initialize(
|
|
7
|
-
@
|
|
6
|
+
def initialize(klass)
|
|
7
|
+
@klass = klass
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def type_cast_for_database(attr_name, value)
|
|
11
|
-
|
|
12
|
-
type = types.type_for_attribute(attr_name)
|
|
11
|
+
type = type_for_attribute(attr_name)
|
|
13
12
|
type.serialize(value)
|
|
14
13
|
end
|
|
15
14
|
|
|
15
|
+
def type_for_attribute(name)
|
|
16
|
+
klass.type_for_attribute(name)
|
|
17
|
+
end
|
|
18
|
+
|
|
16
19
|
private
|
|
17
|
-
attr_reader :
|
|
20
|
+
attr_reader :klass
|
|
18
21
|
end
|
|
19
22
|
end
|
|
20
23
|
end
|
|
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
|
14
14
|
module ClassMethods
|
|
15
15
|
# Validates that the specified attributes are not present (as defined by
|
|
16
16
|
# Object#present?). If the attribute is an association, the associated object
|
|
17
|
-
# is considered
|
|
17
|
+
# is also considered not present if it is marked for destruction.
|
|
18
18
|
#
|
|
19
19
|
# See ActiveModel::Validations::HelperMethods.validates_absence_of for more information.
|
|
20
20
|
def validates_absence_of(*attr_names)
|
|
@@ -2,17 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
module Validations
|
|
5
|
-
class AssociatedValidator < ActiveModel::EachValidator
|
|
5
|
+
class AssociatedValidator < ActiveModel::EachValidator # :nodoc:
|
|
6
6
|
def validate_each(record, attribute, value)
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
context = record_validation_context_for_association(record)
|
|
8
|
+
|
|
9
|
+
if Array(value).reject { |association| valid_object?(association, context) }.any?
|
|
10
|
+
record.errors.add(attribute, :invalid, **options.merge(value: value))
|
|
9
11
|
end
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
private
|
|
15
|
+
def valid_object?(record, context)
|
|
16
|
+
(record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid?(context)
|
|
17
|
+
end
|
|
13
18
|
|
|
14
|
-
def
|
|
15
|
-
|
|
19
|
+
def record_validation_context_for_association(record)
|
|
20
|
+
record.custom_validation_context? ? record.validation_context : nil
|
|
16
21
|
end
|
|
17
22
|
end
|
|
18
23
|
|
|
@@ -43,14 +48,14 @@ module ActiveRecord
|
|
|
43
48
|
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
|
44
49
|
# <tt>on: :custom_validation_context</tt> or
|
|
45
50
|
# <tt>on: [:create, :custom_validation_context]</tt>)
|
|
46
|
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
|
51
|
+
# * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
|
|
47
52
|
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
|
48
53
|
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
|
49
54
|
# proc or string should return or evaluate to a +true+ or +false+ value.
|
|
50
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
|
55
|
+
# * <tt>:unless</tt> - Specifies a method, proc, or string to call to
|
|
51
56
|
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
|
52
57
|
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
53
|
-
# method, proc or string should return or evaluate to a +true+ or +false+
|
|
58
|
+
# method, proc, or string should return or evaluate to a +true+ or +false+
|
|
54
59
|
# value.
|
|
55
60
|
def validates_associated(*attr_names)
|
|
56
61
|
validates_with AssociatedValidator, _merge_attributes(attr_names)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Validations
|
|
5
|
+
class NumericalityValidator < ActiveModel::Validations::NumericalityValidator # :nodoc:
|
|
6
|
+
def validate_each(record, attribute, value, precision: nil, scale: nil)
|
|
7
|
+
precision = [column_precision_for(record, attribute) || Float::DIG, Float::DIG].min
|
|
8
|
+
scale = column_scale_for(record, attribute)
|
|
9
|
+
super(record, attribute, value, precision: precision, scale: scale)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
def column_precision_for(record, attribute)
|
|
14
|
+
record.class.type_for_attribute(attribute.to_s)&.precision
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def column_scale_for(record, attribute)
|
|
18
|
+
record.class.type_for_attribute(attribute.to_s)&.scale
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module ClassMethods
|
|
23
|
+
# Validates whether the value of the specified attribute is numeric by
|
|
24
|
+
# trying to convert it to a float with +Kernel.Float+ (if
|
|
25
|
+
# <tt>only_integer</tt> is +false+) or applying it to the regular
|
|
26
|
+
# expression <tt>/\A[\+\-]?\d+\z/</tt> (if <tt>only_integer</tt> is set to
|
|
27
|
+
# +true+). +Kernel.Float+ precision defaults to the column's precision
|
|
28
|
+
# value or 15.
|
|
29
|
+
#
|
|
30
|
+
# See ActiveModel::Validations::HelperMethods.validates_numericality_of for more information.
|
|
31
|
+
def validates_numericality_of(*attr_names)
|
|
32
|
+
validates_with NumericalityValidator, _merge_attributes(attr_names)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -13,9 +13,8 @@ module ActiveRecord
|
|
|
13
13
|
|
|
14
14
|
module ClassMethods
|
|
15
15
|
# Validates that the specified attributes are not blank (as defined by
|
|
16
|
-
# Object#blank?)
|
|
17
|
-
#
|
|
18
|
-
# on save.
|
|
16
|
+
# Object#blank?). If the attribute is an association, the associated object
|
|
17
|
+
# is also considered blank if it is marked for destruction.
|
|
19
18
|
#
|
|
20
19
|
# class Person < ActiveRecord::Base
|
|
21
20
|
# has_one :face
|
|
@@ -25,41 +24,19 @@ module ActiveRecord
|
|
|
25
24
|
# The face attribute must be in the object and it cannot be blank or marked
|
|
26
25
|
# for destruction.
|
|
27
26
|
#
|
|
28
|
-
# If you want to validate the presence of a boolean field (where the real values
|
|
29
|
-
# are true and false), you will want to use
|
|
30
|
-
# <tt>validates_inclusion_of :field_name, in: [true, false]</tt>.
|
|
31
|
-
#
|
|
32
|
-
# This is due to the way Object#blank? handles boolean values:
|
|
33
|
-
# <tt>false.blank? # => true</tt>.
|
|
34
|
-
#
|
|
35
27
|
# This validator defers to the Active Model validation for presence, adding the
|
|
36
28
|
# check to see that an associated object is not marked for destruction. This
|
|
37
29
|
# prevents the parent object from validating successfully and saving, which then
|
|
38
30
|
# deletes the associated object, thus putting the parent object into an invalid
|
|
39
31
|
# state.
|
|
40
32
|
#
|
|
33
|
+
# See ActiveModel::Validations::HelperMethods.validates_presence_of for
|
|
34
|
+
# more information.
|
|
35
|
+
#
|
|
41
36
|
# NOTE: This validation will not fail while using it with an association
|
|
42
37
|
# if the latter was assigned but not valid. If you want to ensure that
|
|
43
38
|
# it is both present and valid, you also need to use
|
|
44
39
|
# {validates_associated}[rdoc-ref:Validations::ClassMethods#validates_associated].
|
|
45
|
-
#
|
|
46
|
-
# Configuration options:
|
|
47
|
-
# * <tt>:message</tt> - A custom error message (default is: "can't be blank").
|
|
48
|
-
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
|
|
49
|
-
# Runs in all validation contexts by default +nil+. You can pass a symbol
|
|
50
|
-
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
|
51
|
-
# <tt>on: :custom_validation_context</tt> or
|
|
52
|
-
# <tt>on: [:create, :custom_validation_context]</tt>)
|
|
53
|
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
|
|
54
|
-
# the validation should occur (e.g. <tt>if: :allow_validation</tt>, or
|
|
55
|
-
# <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
|
|
56
|
-
# or string should return or evaluate to a +true+ or +false+ value.
|
|
57
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
|
|
58
|
-
# if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
|
59
|
-
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
|
|
60
|
-
# proc or string should return or evaluate to a +true+ or +false+ value.
|
|
61
|
-
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
|
62
|
-
# See ActiveModel::Validations#validates! for more information.
|
|
63
40
|
def validates_presence_of(*attr_names)
|
|
64
41
|
validates_with PresenceValidator, _merge_attributes(attr_names)
|
|
65
42
|
end
|
|
@@ -14,28 +14,40 @@ module ActiveRecord
|
|
|
14
14
|
end
|
|
15
15
|
super
|
|
16
16
|
@klass = options[:class]
|
|
17
|
+
@klass = @klass.superclass if @klass.singleton_class?
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def validate_each(record, attribute, value)
|
|
20
21
|
finder_class = find_finder_class_for(record)
|
|
21
22
|
value = map_enum_attribute(finder_class, attribute, value)
|
|
22
23
|
|
|
24
|
+
return if record.persisted? && !validation_needed?(finder_class, record, attribute)
|
|
25
|
+
|
|
23
26
|
relation = build_relation(finder_class, attribute, value)
|
|
24
27
|
if record.persisted?
|
|
25
28
|
if finder_class.primary_key
|
|
26
|
-
relation = relation.where.not(finder_class.primary_key => record.id_in_database)
|
|
29
|
+
relation = relation.where.not(finder_class.primary_key => [record.id_in_database])
|
|
27
30
|
else
|
|
28
31
|
raise UnknownPrimaryKey.new(finder_class, "Cannot validate uniqueness for persisted record without primary key.")
|
|
29
32
|
end
|
|
30
33
|
end
|
|
31
34
|
relation = scope_relation(record, relation)
|
|
32
|
-
|
|
35
|
+
|
|
36
|
+
if options[:conditions]
|
|
37
|
+
conditions = options[:conditions]
|
|
38
|
+
|
|
39
|
+
relation = if conditions.arity.zero?
|
|
40
|
+
relation.instance_exec(&conditions)
|
|
41
|
+
else
|
|
42
|
+
relation.instance_exec(record, &conditions)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
33
45
|
|
|
34
46
|
if relation.exists?
|
|
35
47
|
error_options = options.except(:case_sensitive, :scope, :conditions)
|
|
36
48
|
error_options[:value] = value
|
|
37
49
|
|
|
38
|
-
record.errors.add(attribute, :taken, error_options)
|
|
50
|
+
record.errors.add(attribute, :taken, **error_options)
|
|
39
51
|
end
|
|
40
52
|
end
|
|
41
53
|
|
|
@@ -55,18 +67,64 @@ module ActiveRecord
|
|
|
55
67
|
class_hierarchy.detect { |klass| !klass.abstract_class? }
|
|
56
68
|
end
|
|
57
69
|
|
|
70
|
+
def validation_needed?(klass, record, attribute)
|
|
71
|
+
return true if options[:conditions] || options.key?(:case_sensitive)
|
|
72
|
+
|
|
73
|
+
scope = Array(options[:scope])
|
|
74
|
+
attributes = scope + [attribute]
|
|
75
|
+
attributes = resolve_attributes(record, attributes)
|
|
76
|
+
|
|
77
|
+
return true if attributes.any? { |attr| record.attribute_changed?(attr) ||
|
|
78
|
+
record.read_attribute(attr).nil? }
|
|
79
|
+
|
|
80
|
+
!covered_by_unique_index?(klass, record, attribute, scope)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def covered_by_unique_index?(klass, record, attribute, scope)
|
|
84
|
+
@covered ||= self.attributes.map(&:to_s).select do |attr|
|
|
85
|
+
attributes = scope + [attr]
|
|
86
|
+
attributes = resolve_attributes(record, attributes)
|
|
87
|
+
|
|
88
|
+
klass.schema_cache.indexes(klass.table_name).any? do |index|
|
|
89
|
+
index.unique &&
|
|
90
|
+
index.where.nil? &&
|
|
91
|
+
(Array(index.columns) - attributes).empty?
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
@covered.include?(attribute.to_s)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def resolve_attributes(record, attributes)
|
|
99
|
+
attributes.flat_map do |attribute|
|
|
100
|
+
reflection = record.class._reflect_on_association(attribute)
|
|
101
|
+
|
|
102
|
+
if reflection.nil?
|
|
103
|
+
attribute.to_s
|
|
104
|
+
elsif reflection.polymorphic?
|
|
105
|
+
[reflection.foreign_key, reflection.foreign_type]
|
|
106
|
+
else
|
|
107
|
+
reflection.foreign_key
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
58
112
|
def build_relation(klass, attribute, value)
|
|
59
113
|
relation = klass.unscoped
|
|
60
|
-
|
|
61
|
-
|
|
114
|
+
# TODO: Add case-sensitive / case-insensitive operators to Arel
|
|
115
|
+
# to no longer need to checkout a connection here.
|
|
116
|
+
comparison = klass.with_connection do |connection|
|
|
117
|
+
relation.bind_attribute(attribute, value) do |attr, bind|
|
|
118
|
+
return relation.none! if bind.unboundable?
|
|
62
119
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
120
|
+
if !options.key?(:case_sensitive) || bind.nil?
|
|
121
|
+
connection.default_uniqueness_comparison(attr, bind)
|
|
122
|
+
elsif options[:case_sensitive]
|
|
123
|
+
connection.case_sensitive_comparison(attr, bind)
|
|
124
|
+
else
|
|
125
|
+
# will use SQL LOWER function before comparison, unless it detects a case insensitive collation
|
|
126
|
+
connection.case_insensitive_comparison(attr, bind)
|
|
127
|
+
end
|
|
70
128
|
end
|
|
71
129
|
end
|
|
72
130
|
|
|
@@ -78,7 +136,7 @@ module ActiveRecord
|
|
|
78
136
|
scope_value = if record.class._reflect_on_association(scope_item)
|
|
79
137
|
record.association(scope_item).reader
|
|
80
138
|
else
|
|
81
|
-
record.
|
|
139
|
+
record.read_attribute(scope_item)
|
|
82
140
|
end
|
|
83
141
|
relation = relation.where(scope_item => scope_value)
|
|
84
142
|
end
|
|
@@ -126,6 +184,17 @@ module ActiveRecord
|
|
|
126
184
|
# validates_uniqueness_of :title, conditions: -> { where.not(status: 'archived') }
|
|
127
185
|
# end
|
|
128
186
|
#
|
|
187
|
+
# To build conditions based on the record's state, define the conditions
|
|
188
|
+
# callable with a parameter, which will be the record itself. This
|
|
189
|
+
# example validates the title is unique for the year of publication:
|
|
190
|
+
#
|
|
191
|
+
# class Article < ActiveRecord::Base
|
|
192
|
+
# validates_uniqueness_of :title, conditions: ->(article) {
|
|
193
|
+
# published_at = article.published_at
|
|
194
|
+
# where(published_at: published_at.beginning_of_year..published_at.end_of_year)
|
|
195
|
+
# }
|
|
196
|
+
# end
|
|
197
|
+
#
|
|
129
198
|
# When the record is created, a check is performed to make sure that no
|
|
130
199
|
# record exists in the database with the given value for the specified
|
|
131
200
|
# attribute (that maps to a column). When the record is updated,
|
|
@@ -141,19 +210,19 @@ module ActiveRecord
|
|
|
141
210
|
# <tt>WHERE</tt> SQL fragment to limit the uniqueness constraint lookup
|
|
142
211
|
# (e.g. <tt>conditions: -> { where(status: 'active') }</tt>).
|
|
143
212
|
# * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
|
|
144
|
-
# non-text columns
|
|
213
|
+
# non-text columns. The default behavior respects the default database collation.
|
|
145
214
|
# * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the
|
|
146
215
|
# attribute is +nil+ (default is +false+).
|
|
147
216
|
# * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
|
|
148
217
|
# attribute is blank (default is +false+).
|
|
149
|
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
|
218
|
+
# * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
|
|
150
219
|
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
|
151
220
|
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
|
152
221
|
# proc or string should return or evaluate to a +true+ or +false+ value.
|
|
153
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
|
222
|
+
# * <tt>:unless</tt> - Specifies a method, proc, or string to call to
|
|
154
223
|
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
|
155
224
|
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
156
|
-
# method, proc or string should return or evaluate to a +true+ or +false+
|
|
225
|
+
# method, proc, or string should return or evaluate to a +true+ or +false+
|
|
157
226
|
# value.
|
|
158
227
|
#
|
|
159
228
|
# === Concurrency and integrity
|
|
@@ -201,7 +270,7 @@ module ActiveRecord
|
|
|
201
270
|
# When the database catches such a duplicate insertion,
|
|
202
271
|
# {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] will raise an ActiveRecord::StatementInvalid
|
|
203
272
|
# exception. You can either choose to let this error propagate (which
|
|
204
|
-
# will result in the default Rails exception page being shown), or you
|
|
273
|
+
# will result in the default \Rails exception page being shown), or you
|
|
205
274
|
# can catch it and restart the transaction (e.g. by telling the user
|
|
206
275
|
# that the title already exists, and asking them to re-enter the title).
|
|
207
276
|
# This technique is also known as
|
|
@@ -216,6 +285,7 @@ module ActiveRecord
|
|
|
216
285
|
# The following bundled adapters throw the ActiveRecord::RecordNotUnique exception:
|
|
217
286
|
#
|
|
218
287
|
# * ActiveRecord::ConnectionAdapters::Mysql2Adapter.
|
|
288
|
+
# * ActiveRecord::ConnectionAdapters::TrilogyAdapter.
|
|
219
289
|
# * ActiveRecord::ConnectionAdapters::SQLite3Adapter.
|
|
220
290
|
# * ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.
|
|
221
291
|
def validates_uniqueness_of(*attr_names)
|
|
@@ -30,26 +30,27 @@ module ActiveRecord
|
|
|
30
30
|
|
|
31
31
|
# = Active Record \Validations
|
|
32
32
|
#
|
|
33
|
-
# Active Record includes the majority of its validations from ActiveModel::Validations
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
33
|
+
# Active Record includes the majority of its validations from ActiveModel::Validations.
|
|
34
|
+
#
|
|
35
|
+
# In Active Record, all validations are performed on save by default.
|
|
36
|
+
# Validations accept the <tt>:on</tt> argument to define the context where
|
|
37
|
+
# the validations are active. Active Record will pass either the context of
|
|
38
|
+
# <tt>:create</tt> or <tt>:update</tt> depending on whether the model is a
|
|
37
39
|
# {new_record?}[rdoc-ref:Persistence#new_record?].
|
|
38
40
|
module Validations
|
|
39
41
|
extend ActiveSupport::Concern
|
|
40
|
-
include ActiveModel::Validations
|
|
41
42
|
|
|
42
43
|
# The validation process on save can be skipped by passing <tt>validate: false</tt>.
|
|
43
44
|
# The validation context can be changed by passing <tt>context: context</tt>.
|
|
44
45
|
# The regular {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] method is replaced
|
|
45
46
|
# with this when the validations module is mixed in, which it is by default.
|
|
46
|
-
def save(options
|
|
47
|
+
def save(**options)
|
|
47
48
|
perform_validations(options) ? super : false
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
# Attempts to save the record just like {ActiveRecord::Base#save}[rdoc-ref:Base#save] but
|
|
51
52
|
# will raise an ActiveRecord::RecordInvalid exception instead of returning +false+ if the record is not valid.
|
|
52
|
-
def save!(options
|
|
53
|
+
def save!(**options)
|
|
53
54
|
perform_validations(options) ? super : raise_validation_error
|
|
54
55
|
end
|
|
55
56
|
|
|
@@ -60,6 +61,8 @@ module ActiveRecord
|
|
|
60
61
|
#
|
|
61
62
|
# If the argument is +false+ (default is +nil+), the context is set to <tt>:create</tt> if
|
|
62
63
|
# {new_record?}[rdoc-ref:Persistence#new_record?] is +true+, and to <tt>:update</tt> if it is not.
|
|
64
|
+
# If the argument is an array of contexts, <tt>post.valid?([:create, :update])</tt>, the validations are
|
|
65
|
+
# run within multiple contexts.
|
|
63
66
|
#
|
|
64
67
|
# \Validations with no <tt>:on</tt> option will run no matter the context. \Validations with
|
|
65
68
|
# some <tt>:on</tt> option will only run in the specified context.
|
|
@@ -71,8 +74,11 @@ module ActiveRecord
|
|
|
71
74
|
|
|
72
75
|
alias_method :validate, :valid?
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
def custom_validation_context? # :nodoc:
|
|
78
|
+
validation_context && [:create, :update].exclude?(validation_context)
|
|
79
|
+
end
|
|
75
80
|
|
|
81
|
+
private
|
|
76
82
|
def default_validation_context
|
|
77
83
|
new_record? ? :create : :update
|
|
78
84
|
end
|
|
@@ -92,3 +98,4 @@ require "active_record/validations/uniqueness"
|
|
|
92
98
|
require "active_record/validations/presence"
|
|
93
99
|
require "active_record/validations/absence"
|
|
94
100
|
require "active_record/validations/length"
|
|
101
|
+
require "active_record/validations/numericality"
|