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
data/lib/active_record/core.rb
CHANGED
|
@@ -1,29 +1,50 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "active_support/core_ext/
|
|
4
|
-
require "active_support/core_ext/
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
|
4
|
+
require "active_support/core_ext/module/delegation"
|
|
5
5
|
require "active_support/parameter_filter"
|
|
6
6
|
require "concurrent/map"
|
|
7
7
|
|
|
8
8
|
module ActiveRecord
|
|
9
|
+
# = Active Record \Core
|
|
9
10
|
module Core
|
|
10
11
|
extend ActiveSupport::Concern
|
|
12
|
+
include ActiveModel::Access
|
|
11
13
|
|
|
12
14
|
included do
|
|
13
15
|
##
|
|
14
16
|
# :singleton-method:
|
|
15
17
|
#
|
|
16
|
-
# Accepts a logger conforming to the interface of Log4r
|
|
17
|
-
# passed on to any new database
|
|
18
|
-
#
|
|
19
|
-
|
|
18
|
+
# Accepts a logger conforming to the interface of Log4r or the default
|
|
19
|
+
# Ruby +Logger+ class, which is then passed on to any new database
|
|
20
|
+
# connections made. You can retrieve this logger by calling +logger+ on
|
|
21
|
+
# either an Active Record model class or an Active Record model instance.
|
|
22
|
+
class_attribute :logger, instance_writer: false
|
|
23
|
+
|
|
24
|
+
class_attribute :_destroy_association_async_job, instance_accessor: false, default: "ActiveRecord::DestroyAssociationAsyncJob"
|
|
25
|
+
|
|
26
|
+
# The job class used to destroy associations in the background.
|
|
27
|
+
def self.destroy_association_async_job
|
|
28
|
+
if _destroy_association_async_job.is_a?(String)
|
|
29
|
+
self._destroy_association_async_job = _destroy_association_async_job.constantize
|
|
30
|
+
end
|
|
31
|
+
_destroy_association_async_job
|
|
32
|
+
rescue NameError => error
|
|
33
|
+
raise NameError, "Unable to load destroy_association_async_job: #{error.message}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
singleton_class.alias_method :destroy_association_async_job=, :_destroy_association_async_job=
|
|
37
|
+
delegate :destroy_association_async_job, to: :class
|
|
20
38
|
|
|
21
39
|
##
|
|
22
40
|
# :singleton-method:
|
|
23
41
|
#
|
|
24
|
-
# Specifies
|
|
25
|
-
#
|
|
26
|
-
|
|
42
|
+
# Specifies the maximum number of records that will be destroyed in a
|
|
43
|
+
# single background job by the <tt>dependent: :destroy_async</tt>
|
|
44
|
+
# association option. When +nil+ (default), all dependent records will be
|
|
45
|
+
# destroyed in a single background job. If specified, the records to be
|
|
46
|
+
# destroyed will be split into multiple background jobs.
|
|
47
|
+
class_attribute :destroy_association_async_batch_size, instance_writer: false, instance_predicate: false, default: nil
|
|
27
48
|
|
|
28
49
|
##
|
|
29
50
|
# Contains the database configuration - as is typically stored in config/database.yml -
|
|
@@ -33,114 +54,200 @@ module ActiveRecord
|
|
|
33
54
|
#
|
|
34
55
|
# development:
|
|
35
56
|
# adapter: sqlite3
|
|
36
|
-
# database:
|
|
57
|
+
# database: storage/development.sqlite3
|
|
37
58
|
#
|
|
38
59
|
# production:
|
|
39
60
|
# adapter: sqlite3
|
|
40
|
-
# database:
|
|
61
|
+
# database: storage/production.sqlite3
|
|
41
62
|
#
|
|
42
63
|
# ...would result in ActiveRecord::Base.configurations to look like this:
|
|
43
64
|
#
|
|
44
65
|
# #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
|
|
45
66
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
|
46
|
-
# @
|
|
67
|
+
# @name="primary", @config={adapter: "sqlite3", database: "storage/development.sqlite3"}>,
|
|
47
68
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
|
|
48
|
-
# @
|
|
69
|
+
# @name="primary", @config={adapter: "sqlite3", database: "storage/production.sqlite3"}>
|
|
49
70
|
# ]>
|
|
50
71
|
def self.configurations=(config)
|
|
51
72
|
@@configurations = ActiveRecord::DatabaseConfigurations.new(config)
|
|
52
73
|
end
|
|
53
74
|
self.configurations = {}
|
|
54
75
|
|
|
55
|
-
# Returns fully resolved ActiveRecord::DatabaseConfigurations object
|
|
76
|
+
# Returns a fully resolved ActiveRecord::DatabaseConfigurations object.
|
|
56
77
|
def self.configurations
|
|
57
78
|
@@configurations
|
|
58
79
|
end
|
|
59
80
|
|
|
60
81
|
##
|
|
61
82
|
# :singleton-method:
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
|
|
83
|
+
# Force enumeration of all columns in SELECT statements.
|
|
84
|
+
# e.g. <tt>SELECT first_name, last_name FROM ...</tt> instead of <tt>SELECT * FROM ...</tt>
|
|
85
|
+
# This avoids +PreparedStatementCacheExpired+ errors when a column is added
|
|
86
|
+
# to the database while the app is running.
|
|
87
|
+
class_attribute :enumerate_columns_in_select_statements, instance_accessor: false, default: false
|
|
65
88
|
|
|
66
|
-
|
|
67
|
-
# :singleton-method:
|
|
68
|
-
# Specifies the format to use when dumping the database schema with Rails'
|
|
69
|
-
# Rakefile. If :sql, the schema is dumped as (potentially database-
|
|
70
|
-
# specific) SQL statements. If :ruby, the schema is dumped as an
|
|
71
|
-
# ActiveRecord::Schema file which can be loaded into any database that
|
|
72
|
-
# supports migrations. Use :ruby if you want to have different database
|
|
73
|
-
# adapters for, e.g., your development and test environments.
|
|
74
|
-
mattr_accessor :schema_format, instance_writer: false, default: :ruby
|
|
89
|
+
class_attribute :belongs_to_required_by_default, instance_accessor: false
|
|
75
90
|
|
|
76
|
-
|
|
77
|
-
# :singleton-method:
|
|
78
|
-
# Specifies if an error should be raised if the query has an order being
|
|
79
|
-
# ignored when doing batch queries. Useful in applications where the
|
|
80
|
-
# scope being ignored is error-worthy, rather than a warning.
|
|
81
|
-
mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
|
|
91
|
+
class_attribute :strict_loading_by_default, instance_accessor: false, default: false
|
|
82
92
|
|
|
83
|
-
|
|
84
|
-
# Specify the behavior for unsafe raw query methods. Values are as follows
|
|
85
|
-
# deprecated - Warnings are logged when unsafe raw SQL is passed to
|
|
86
|
-
# query methods.
|
|
87
|
-
# disabled - Unsafe raw SQL passed to query methods results in
|
|
88
|
-
# UnknownAttributeReference exception.
|
|
89
|
-
mattr_accessor :allow_unsafe_raw_sql, instance_writer: false, default: :deprecated
|
|
93
|
+
class_attribute :has_many_inversing, instance_accessor: false, default: false
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
# :singleton-method:
|
|
93
|
-
# Specify whether or not to use timestamps for migration versions
|
|
94
|
-
mattr_accessor :timestamped_migrations, instance_writer: false, default: true
|
|
95
|
+
class_attribute :run_commit_callbacks_on_first_saved_instances_in_transaction, instance_accessor: false, default: true
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
# :singleton-method:
|
|
98
|
-
# Specify whether schema dump should happen at the end of the
|
|
99
|
-
# db:migrate rails command. This is true by default, which is useful for the
|
|
100
|
-
# development environment. This should ideally be false in the production
|
|
101
|
-
# environment where dumping schema is rarely needed.
|
|
102
|
-
mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
|
|
97
|
+
class_attribute :default_connection_handler, instance_writer: false
|
|
103
98
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
# of schema_search_path, or a string of comma separated schemas for a
|
|
110
|
-
# custom list.
|
|
111
|
-
mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
|
|
99
|
+
class_attribute :default_role, instance_writer: false
|
|
100
|
+
|
|
101
|
+
class_attribute :default_shard, instance_writer: false
|
|
102
|
+
|
|
103
|
+
class_attribute :shard_selector, instance_accessor: false, default: nil
|
|
112
104
|
|
|
113
105
|
##
|
|
114
106
|
# :singleton-method:
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
|
|
107
|
+
#
|
|
108
|
+
# Specifies the attributes that will be included in the output of the
|
|
109
|
+
# #inspect method:
|
|
110
|
+
#
|
|
111
|
+
# Post.attributes_for_inspect = [:id, :title]
|
|
112
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
|
|
113
|
+
#
|
|
114
|
+
# When set to `:all` inspect will list all the record's attributes:
|
|
115
|
+
#
|
|
116
|
+
# Post.attributes_for_inspect = :all
|
|
117
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
|
118
|
+
class_attribute :attributes_for_inspect, instance_accessor: false, default: :all
|
|
120
119
|
|
|
121
|
-
|
|
120
|
+
def self.application_record_class? # :nodoc:
|
|
121
|
+
if ActiveRecord.application_record_class
|
|
122
|
+
self == ActiveRecord.application_record_class
|
|
123
|
+
else
|
|
124
|
+
if defined?(ApplicationRecord) && self == ApplicationRecord
|
|
125
|
+
true
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
122
129
|
|
|
123
|
-
|
|
130
|
+
self.filter_attributes = []
|
|
124
131
|
|
|
125
|
-
|
|
132
|
+
def self.connection_handler
|
|
133
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] || default_connection_handler
|
|
134
|
+
end
|
|
126
135
|
|
|
127
|
-
|
|
136
|
+
def self.connection_handler=(handler)
|
|
137
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
|
|
138
|
+
end
|
|
128
139
|
|
|
129
|
-
|
|
140
|
+
def self.asynchronous_queries_session # :nodoc:
|
|
141
|
+
asynchronous_queries_tracker.current_session
|
|
142
|
+
end
|
|
130
143
|
|
|
131
|
-
|
|
144
|
+
def self.asynchronous_queries_tracker # :nodoc:
|
|
145
|
+
ActiveSupport::IsolatedExecutionState[:active_record_asynchronous_queries_tracker] ||= \
|
|
146
|
+
AsynchronousQueriesTracker.new
|
|
147
|
+
end
|
|
132
148
|
|
|
133
|
-
|
|
149
|
+
# Returns the symbol representing the current connected role.
|
|
150
|
+
#
|
|
151
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
|
152
|
+
# ActiveRecord::Base.current_role #=> :writing
|
|
153
|
+
# end
|
|
154
|
+
#
|
|
155
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
|
156
|
+
# ActiveRecord::Base.current_role #=> :reading
|
|
157
|
+
# end
|
|
158
|
+
def self.current_role
|
|
159
|
+
connected_to_stack.reverse_each do |hash|
|
|
160
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
|
161
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
|
|
162
|
+
end
|
|
134
163
|
|
|
135
|
-
|
|
136
|
-
Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
|
|
164
|
+
default_role
|
|
137
165
|
end
|
|
138
166
|
|
|
139
|
-
|
|
140
|
-
|
|
167
|
+
# Returns the symbol representing the current connected shard.
|
|
168
|
+
#
|
|
169
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
|
170
|
+
# ActiveRecord::Base.current_shard #=> :default
|
|
171
|
+
# end
|
|
172
|
+
#
|
|
173
|
+
# ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
|
|
174
|
+
# ActiveRecord::Base.current_shard #=> :one
|
|
175
|
+
# end
|
|
176
|
+
def self.current_shard
|
|
177
|
+
connected_to_stack.reverse_each do |hash|
|
|
178
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
|
|
179
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_class_for_self)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
default_shard
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Returns the symbol representing the current setting for
|
|
186
|
+
# preventing writes.
|
|
187
|
+
#
|
|
188
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
|
189
|
+
# ActiveRecord::Base.current_preventing_writes #=> true
|
|
190
|
+
# end
|
|
191
|
+
#
|
|
192
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
|
193
|
+
# ActiveRecord::Base.current_preventing_writes #=> false
|
|
194
|
+
# end
|
|
195
|
+
def self.current_preventing_writes
|
|
196
|
+
connected_to_stack.reverse_each do |hash|
|
|
197
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
|
198
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
false
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def self.connected_to_stack # :nodoc:
|
|
205
|
+
if connected_to_stack = ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack]
|
|
206
|
+
connected_to_stack
|
|
207
|
+
else
|
|
208
|
+
connected_to_stack = Concurrent::Array.new
|
|
209
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack] = connected_to_stack
|
|
210
|
+
connected_to_stack
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def self.connection_class=(b) # :nodoc:
|
|
215
|
+
@connection_class = b
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def self.connection_class # :nodoc:
|
|
219
|
+
@connection_class ||= false
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def self.connection_class? # :nodoc:
|
|
223
|
+
self.connection_class
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def self.connection_class_for_self # :nodoc:
|
|
227
|
+
klass = self
|
|
228
|
+
|
|
229
|
+
until klass == Base
|
|
230
|
+
break if klass.connection_class?
|
|
231
|
+
klass = klass.superclass
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
klass
|
|
141
235
|
end
|
|
142
236
|
|
|
143
237
|
self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
|
|
238
|
+
self.default_role = ActiveRecord.writing_role
|
|
239
|
+
self.default_shard = :default
|
|
240
|
+
|
|
241
|
+
def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
|
|
242
|
+
case ActiveRecord.action_on_strict_loading_violation
|
|
243
|
+
when :raise
|
|
244
|
+
message = reflection.strict_loading_violation_message(owner)
|
|
245
|
+
raise ActiveRecord::StrictLoadingViolationError.new(message)
|
|
246
|
+
when :log
|
|
247
|
+
name = "strict_loading_violation.active_record"
|
|
248
|
+
ActiveSupport::Notifications.instrument(name, owner: owner, reflection: reflection)
|
|
249
|
+
end
|
|
250
|
+
end
|
|
144
251
|
end
|
|
145
252
|
|
|
146
253
|
module ClassMethods
|
|
@@ -148,67 +255,68 @@ module ActiveRecord
|
|
|
148
255
|
@find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
|
|
149
256
|
end
|
|
150
257
|
|
|
151
|
-
def inherited(child_class) # :nodoc:
|
|
152
|
-
# initialize cache at class definition for thread safety
|
|
153
|
-
child_class.initialize_find_by_cache
|
|
154
|
-
super
|
|
155
|
-
end
|
|
156
|
-
|
|
157
258
|
def find(*ids) # :nodoc:
|
|
158
259
|
# We don't have cache keys for this stuff yet
|
|
159
260
|
return super unless ids.length == 1
|
|
160
|
-
return super if block_given? ||
|
|
161
|
-
primary_key.nil? ||
|
|
162
|
-
scope_attributes? ||
|
|
163
|
-
columns_hash.key?(inheritance_column) && !base_class?
|
|
261
|
+
return super if block_given? || primary_key.nil? || scope_attributes?
|
|
164
262
|
|
|
165
263
|
id = ids.first
|
|
166
264
|
|
|
167
265
|
return super if StatementCache.unsupported_value?(id)
|
|
168
266
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
statement = cached_find_by_statement(key) { |params|
|
|
172
|
-
where(key => params.bind).limit(1)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
record = statement.execute([id], connection)&.first
|
|
176
|
-
unless record
|
|
177
|
-
raise RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id)
|
|
178
|
-
end
|
|
179
|
-
record
|
|
267
|
+
cached_find_by([primary_key], [id]) ||
|
|
268
|
+
raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id.inspect}", name, primary_key, id))
|
|
180
269
|
end
|
|
181
270
|
|
|
182
271
|
def find_by(*args) # :nodoc:
|
|
183
|
-
return super if scope_attributes?
|
|
184
|
-
columns_hash.key?(inheritance_column) && !base_class?
|
|
272
|
+
return super if scope_attributes?
|
|
185
273
|
|
|
186
274
|
hash = args.first
|
|
275
|
+
return super unless Hash === hash
|
|
276
|
+
|
|
277
|
+
hash = hash.each_with_object({}) do |(key, value), h|
|
|
278
|
+
key = key.to_s
|
|
279
|
+
key = attribute_aliases[key] || key
|
|
280
|
+
|
|
281
|
+
return super if reflect_on_aggregation(key)
|
|
282
|
+
|
|
283
|
+
reflection = _reflect_on_association(key)
|
|
284
|
+
|
|
285
|
+
if !reflection
|
|
286
|
+
value = value.id if value.respond_to?(:id)
|
|
287
|
+
elsif reflection.belongs_to? && !reflection.polymorphic?
|
|
288
|
+
key = reflection.join_foreign_key
|
|
289
|
+
pkey = reflection.join_primary_key
|
|
290
|
+
|
|
291
|
+
if pkey.is_a?(Array)
|
|
292
|
+
if pkey.all? { |attribute| value.respond_to?(attribute) }
|
|
293
|
+
value = pkey.map do |attribute|
|
|
294
|
+
if attribute == "id"
|
|
295
|
+
value.id_value
|
|
296
|
+
else
|
|
297
|
+
value.public_send(attribute)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
composite_primary_key = true
|
|
301
|
+
end
|
|
302
|
+
else
|
|
303
|
+
value = value.public_send(pkey) if value.respond_to?(pkey)
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
if !composite_primary_key &&
|
|
308
|
+
(!columns_hash.key?(key) || StatementCache.unsupported_value?(value))
|
|
309
|
+
return super
|
|
310
|
+
end
|
|
187
311
|
|
|
188
|
-
|
|
189
|
-
StatementCache.unsupported_value?(v)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
# We can't cache Post.find_by(author: david) ...yet
|
|
193
|
-
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
|
194
|
-
|
|
195
|
-
keys = hash.keys
|
|
196
|
-
|
|
197
|
-
statement = cached_find_by_statement(keys) { |params|
|
|
198
|
-
wheres = keys.each_with_object({}) { |param, o|
|
|
199
|
-
o[param] = params.bind
|
|
200
|
-
}
|
|
201
|
-
where(wheres).limit(1)
|
|
202
|
-
}
|
|
203
|
-
begin
|
|
204
|
-
statement.execute(hash.values, connection)&.first
|
|
205
|
-
rescue TypeError
|
|
206
|
-
raise ActiveRecord::StatementInvalid
|
|
312
|
+
h[key] = value
|
|
207
313
|
end
|
|
314
|
+
|
|
315
|
+
cached_find_by(hash.keys, hash.values)
|
|
208
316
|
end
|
|
209
317
|
|
|
210
318
|
def find_by!(*args) # :nodoc:
|
|
211
|
-
find_by(*args) ||
|
|
319
|
+
find_by(*args) || where(*args).raise_record_not_found_exception!
|
|
212
320
|
end
|
|
213
321
|
|
|
214
322
|
def initialize_generated_modules # :nodoc:
|
|
@@ -227,24 +335,38 @@ module ActiveRecord
|
|
|
227
335
|
|
|
228
336
|
# Returns columns which shouldn't be exposed while calling +#inspect+.
|
|
229
337
|
def filter_attributes
|
|
230
|
-
if
|
|
231
|
-
@filter_attributes
|
|
232
|
-
else
|
|
338
|
+
if @filter_attributes.nil?
|
|
233
339
|
superclass.filter_attributes
|
|
340
|
+
else
|
|
341
|
+
@filter_attributes
|
|
234
342
|
end
|
|
235
343
|
end
|
|
236
344
|
|
|
237
345
|
# Specifies columns which shouldn't be exposed while calling +#inspect+.
|
|
238
|
-
|
|
346
|
+
def filter_attributes=(filter_attributes)
|
|
347
|
+
@inspection_filter = nil
|
|
348
|
+
@filter_attributes = filter_attributes
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def inspection_filter # :nodoc:
|
|
352
|
+
if @filter_attributes.nil?
|
|
353
|
+
superclass.inspection_filter
|
|
354
|
+
else
|
|
355
|
+
@inspection_filter ||= begin
|
|
356
|
+
mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
|
|
357
|
+
ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end
|
|
239
361
|
|
|
240
362
|
# Returns a string like 'Post(id:integer, title:string, body:text)'
|
|
241
363
|
def inspect # :nodoc:
|
|
242
|
-
if self == Base
|
|
364
|
+
if self == Base || singleton_class?
|
|
243
365
|
super
|
|
244
366
|
elsif abstract_class?
|
|
245
367
|
"#{super}(abstract)"
|
|
246
|
-
elsif !connected?
|
|
247
|
-
"#{super} (call '#{super}.
|
|
368
|
+
elsif !schema_loaded? && !connected?
|
|
369
|
+
"#{super} (call '#{super}.load_schema' to load schema informations)"
|
|
248
370
|
elsif table_exists?
|
|
249
371
|
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
|
|
250
372
|
"#{super}(#{attr_list})"
|
|
@@ -253,24 +375,9 @@ module ActiveRecord
|
|
|
253
375
|
end
|
|
254
376
|
end
|
|
255
377
|
|
|
256
|
-
#
|
|
257
|
-
def ===(object) # :nodoc:
|
|
258
|
-
object.is_a?(self)
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
# Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
|
|
262
|
-
#
|
|
263
|
-
# class Post < ActiveRecord::Base
|
|
264
|
-
# scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
|
|
265
|
-
# end
|
|
378
|
+
# Returns an instance of +Arel::Table+ loaded with the current table name.
|
|
266
379
|
def arel_table # :nodoc:
|
|
267
|
-
@arel_table ||= Arel::Table.new(table_name,
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
def arel_attribute(name, table = arel_table) # :nodoc:
|
|
271
|
-
name = name.to_s
|
|
272
|
-
name = attribute_aliases[name] || name
|
|
273
|
-
table[name]
|
|
380
|
+
@arel_table ||= Arel::Table.new(table_name, klass: self)
|
|
274
381
|
end
|
|
275
382
|
|
|
276
383
|
def predicate_builder # :nodoc:
|
|
@@ -281,15 +388,32 @@ module ActiveRecord
|
|
|
281
388
|
TypeCaster::Map.new(self)
|
|
282
389
|
end
|
|
283
390
|
|
|
284
|
-
def
|
|
285
|
-
|
|
391
|
+
def cached_find_by_statement(connection, key, &block) # :nodoc:
|
|
392
|
+
cache = @find_by_statement_cache[connection.prepared_statements]
|
|
393
|
+
cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
|
|
286
394
|
end
|
|
287
395
|
|
|
288
396
|
private
|
|
397
|
+
def inherited(subclass)
|
|
398
|
+
super
|
|
289
399
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
400
|
+
# initialize cache at class definition for thread safety
|
|
401
|
+
subclass.initialize_find_by_cache
|
|
402
|
+
unless subclass.base_class?
|
|
403
|
+
klass = self
|
|
404
|
+
until klass.base_class?
|
|
405
|
+
klass.initialize_find_by_cache
|
|
406
|
+
klass = klass.superclass
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
subclass.class_eval do
|
|
411
|
+
@arel_table = nil
|
|
412
|
+
@predicate_builder = nil
|
|
413
|
+
@inspection_filter = nil
|
|
414
|
+
@filter_attributes ||= nil
|
|
415
|
+
@generated_association_methods ||= nil
|
|
416
|
+
end
|
|
293
417
|
end
|
|
294
418
|
|
|
295
419
|
def relation
|
|
@@ -297,7 +421,6 @@ module ActiveRecord
|
|
|
297
421
|
|
|
298
422
|
if finder_needs_type_condition? && !ignore_default_scope?
|
|
299
423
|
relation.where!(type_condition)
|
|
300
|
-
relation.create_with!(inheritance_column.to_s => sti_name)
|
|
301
424
|
else
|
|
302
425
|
relation
|
|
303
426
|
end
|
|
@@ -306,6 +429,27 @@ module ActiveRecord
|
|
|
306
429
|
def table_metadata
|
|
307
430
|
TableMetadata.new(self, arel_table)
|
|
308
431
|
end
|
|
432
|
+
|
|
433
|
+
def cached_find_by(keys, values)
|
|
434
|
+
with_connection do |connection|
|
|
435
|
+
statement = cached_find_by_statement(connection, keys) { |params|
|
|
436
|
+
wheres = keys.index_with do |key|
|
|
437
|
+
if key.is_a?(Array)
|
|
438
|
+
[key.map { params.bind }]
|
|
439
|
+
else
|
|
440
|
+
params.bind
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
where(wheres).limit(1)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
begin
|
|
447
|
+
statement.execute(values.flatten, connection, allow_retry: true).first
|
|
448
|
+
rescue TypeError
|
|
449
|
+
raise ActiveRecord::StatementInvalid
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
end
|
|
309
453
|
end
|
|
310
454
|
|
|
311
455
|
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
|
|
@@ -313,7 +457,7 @@ module ActiveRecord
|
|
|
313
457
|
# In both instances, valid attribute keys are determined by the column names of the associated table --
|
|
314
458
|
# hence you can't have attributes that aren't part of the table columns.
|
|
315
459
|
#
|
|
316
|
-
# ==== Example
|
|
460
|
+
# ==== Example
|
|
317
461
|
# # Instantiates a single new object
|
|
318
462
|
# User.new(first_name: 'Jamie')
|
|
319
463
|
def initialize(attributes = nil)
|
|
@@ -323,7 +467,7 @@ module ActiveRecord
|
|
|
323
467
|
init_internals
|
|
324
468
|
initialize_internals_callback
|
|
325
469
|
|
|
326
|
-
|
|
470
|
+
super
|
|
327
471
|
|
|
328
472
|
yield self if block_given?
|
|
329
473
|
_run_initialize_callbacks
|
|
@@ -344,7 +488,7 @@ module ActiveRecord
|
|
|
344
488
|
# post.init_with(coder)
|
|
345
489
|
# post.title # => 'hello world'
|
|
346
490
|
def init_with(coder, &block)
|
|
347
|
-
coder = LegacyYamlAdapter.convert(
|
|
491
|
+
coder = LegacyYamlAdapter.convert(coder)
|
|
348
492
|
attributes = self.class.yaml_encoder.decode(coder)
|
|
349
493
|
init_with_attributes(attributes, coder["new_record"], &block)
|
|
350
494
|
end
|
|
@@ -391,19 +535,24 @@ module ActiveRecord
|
|
|
391
535
|
# only, not its associations. The extent of a "deep" copy is application
|
|
392
536
|
# specific and is therefore left to the application to implement according
|
|
393
537
|
# to its need.
|
|
394
|
-
# The dup method does not preserve the timestamps (created|updated)_(at|on)
|
|
538
|
+
# The dup method does not preserve the timestamps (created|updated)_(at|on)
|
|
539
|
+
# and locking column.
|
|
395
540
|
|
|
396
541
|
##
|
|
397
542
|
def initialize_dup(other) # :nodoc:
|
|
398
543
|
@attributes = @attributes.deep_dup
|
|
399
|
-
|
|
544
|
+
if self.class.composite_primary_key?
|
|
545
|
+
@primary_key.each { |key| @attributes.reset(key) }
|
|
546
|
+
else
|
|
547
|
+
@attributes.reset(@primary_key)
|
|
548
|
+
end
|
|
400
549
|
|
|
401
550
|
_run_initialize_callbacks
|
|
402
551
|
|
|
403
552
|
@new_record = true
|
|
553
|
+
@previously_new_record = false
|
|
404
554
|
@destroyed = false
|
|
405
555
|
@_start_transaction_state = nil
|
|
406
|
-
@transaction_state = nil
|
|
407
556
|
|
|
408
557
|
super
|
|
409
558
|
end
|
|
@@ -426,6 +575,35 @@ module ActiveRecord
|
|
|
426
575
|
coder["active_record_yaml_version"] = 2
|
|
427
576
|
end
|
|
428
577
|
|
|
578
|
+
##
|
|
579
|
+
# :method: slice
|
|
580
|
+
#
|
|
581
|
+
# :call-seq: slice(*methods)
|
|
582
|
+
#
|
|
583
|
+
# Returns a hash of the given methods with their names as keys and returned
|
|
584
|
+
# values as values.
|
|
585
|
+
#
|
|
586
|
+
# topic = Topic.new(title: "Budget", author_name: "Jason")
|
|
587
|
+
# topic.slice(:title, :author_name)
|
|
588
|
+
# # => { "title" => "Budget", "author_name" => "Jason" }
|
|
589
|
+
#
|
|
590
|
+
#--
|
|
591
|
+
# Implemented by ActiveModel::Access#slice.
|
|
592
|
+
|
|
593
|
+
##
|
|
594
|
+
# :method: values_at
|
|
595
|
+
#
|
|
596
|
+
# :call-seq: values_at(*methods)
|
|
597
|
+
#
|
|
598
|
+
# Returns an array of the values returned by the given methods.
|
|
599
|
+
#
|
|
600
|
+
# topic = Topic.new(title: "Budget", author_name: "Jason")
|
|
601
|
+
# topic.values_at(:title, :author_name)
|
|
602
|
+
# # => ["Budget", "Jason"]
|
|
603
|
+
#
|
|
604
|
+
#--
|
|
605
|
+
# Implemented by ActiveModel::Access#values_at.
|
|
606
|
+
|
|
429
607
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
|
430
608
|
# is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
|
|
431
609
|
#
|
|
@@ -438,7 +616,7 @@ module ActiveRecord
|
|
|
438
616
|
def ==(comparison_object)
|
|
439
617
|
super ||
|
|
440
618
|
comparison_object.instance_of?(self.class) &&
|
|
441
|
-
|
|
619
|
+
primary_key_values_present? &&
|
|
442
620
|
comparison_object.id == id
|
|
443
621
|
end
|
|
444
622
|
alias :eql? :==
|
|
@@ -446,7 +624,9 @@ module ActiveRecord
|
|
|
446
624
|
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
|
447
625
|
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
|
448
626
|
def hash
|
|
449
|
-
|
|
627
|
+
id = self.id
|
|
628
|
+
|
|
629
|
+
if primary_key_values_present?
|
|
450
630
|
self.class.hash ^ id.hash
|
|
451
631
|
else
|
|
452
632
|
super
|
|
@@ -463,7 +643,6 @@ module ActiveRecord
|
|
|
463
643
|
|
|
464
644
|
# Returns +true+ if the attributes hash has been frozen.
|
|
465
645
|
def frozen?
|
|
466
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
|
467
646
|
@attributes.frozen?
|
|
468
647
|
end
|
|
469
648
|
|
|
@@ -484,13 +663,91 @@ module ActiveRecord
|
|
|
484
663
|
false
|
|
485
664
|
end
|
|
486
665
|
|
|
487
|
-
# Returns +true+ if the record is read only.
|
|
488
|
-
# attributes will be marked as read only since they cannot be saved.
|
|
666
|
+
# Returns +true+ if the record is read only.
|
|
489
667
|
def readonly?
|
|
490
668
|
@readonly
|
|
491
669
|
end
|
|
492
670
|
|
|
493
|
-
#
|
|
671
|
+
# Returns +true+ if the record is in strict_loading mode.
|
|
672
|
+
def strict_loading?
|
|
673
|
+
@strict_loading
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
# Sets the record to strict_loading mode. This will raise an error
|
|
677
|
+
# if the record tries to lazily load an association.
|
|
678
|
+
#
|
|
679
|
+
# NOTE: Strict loading is disabled during validation in order to let the record validate its association.
|
|
680
|
+
#
|
|
681
|
+
# user = User.first
|
|
682
|
+
# user.strict_loading! # => true
|
|
683
|
+
# user.address.city
|
|
684
|
+
# # => ActiveRecord::StrictLoadingViolationError
|
|
685
|
+
# user.comments.to_a
|
|
686
|
+
# # => ActiveRecord::StrictLoadingViolationError
|
|
687
|
+
#
|
|
688
|
+
# ==== Parameters
|
|
689
|
+
#
|
|
690
|
+
# * +value+ - Boolean specifying whether to enable or disable strict loading.
|
|
691
|
+
# * <tt>:mode</tt> - Symbol specifying strict loading mode. Defaults to :all. Using
|
|
692
|
+
# :n_plus_one_only mode will only raise an error if an association that
|
|
693
|
+
# will lead to an n plus one query is lazily loaded.
|
|
694
|
+
#
|
|
695
|
+
# ==== Examples
|
|
696
|
+
#
|
|
697
|
+
# user = User.first
|
|
698
|
+
# user.strict_loading!(false) # => false
|
|
699
|
+
# user.address.city # => "Tatooine"
|
|
700
|
+
# user.comments.to_a # => [#<Comment:0x00...]
|
|
701
|
+
#
|
|
702
|
+
# user.strict_loading!(mode: :n_plus_one_only)
|
|
703
|
+
# user.address.city # => "Tatooine"
|
|
704
|
+
# user.comments.to_a # => [#<Comment:0x00...]
|
|
705
|
+
# user.comments.first.ratings.to_a
|
|
706
|
+
# # => ActiveRecord::StrictLoadingViolationError
|
|
707
|
+
def strict_loading!(value = true, mode: :all)
|
|
708
|
+
unless [:all, :n_plus_one_only].include?(mode)
|
|
709
|
+
raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
@strict_loading_mode = mode
|
|
713
|
+
@strict_loading = value
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
attr_reader :strict_loading_mode
|
|
717
|
+
|
|
718
|
+
# Returns +true+ if the record uses strict_loading with +:n_plus_one_only+ mode enabled.
|
|
719
|
+
def strict_loading_n_plus_one_only?
|
|
720
|
+
@strict_loading_mode == :n_plus_one_only
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# Returns +true+ if the record uses strict_loading with +:all+ mode enabled.
|
|
724
|
+
def strict_loading_all?
|
|
725
|
+
@strict_loading_mode == :all
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
# Prevents records from being written to the database:
|
|
729
|
+
#
|
|
730
|
+
# customer = Customer.new
|
|
731
|
+
# customer.readonly!
|
|
732
|
+
# customer.save # raises ActiveRecord::ReadOnlyRecord
|
|
733
|
+
#
|
|
734
|
+
# customer = Customer.first
|
|
735
|
+
# customer.readonly!
|
|
736
|
+
# customer.update(name: 'New Name') # raises ActiveRecord::ReadOnlyRecord
|
|
737
|
+
#
|
|
738
|
+
# Read-only records cannot be deleted from the database either:
|
|
739
|
+
#
|
|
740
|
+
# customer = Customer.first
|
|
741
|
+
# customer.readonly!
|
|
742
|
+
# customer.destroy # raises ActiveRecord::ReadOnlyRecord
|
|
743
|
+
#
|
|
744
|
+
# Please, note that the objects themselves are still mutable in memory:
|
|
745
|
+
#
|
|
746
|
+
# customer = Customer.new
|
|
747
|
+
# customer.readonly!
|
|
748
|
+
# customer.name = 'New Name' # OK
|
|
749
|
+
#
|
|
750
|
+
# but you won't be able to persist the changes.
|
|
494
751
|
def readonly!
|
|
495
752
|
@readonly = true
|
|
496
753
|
end
|
|
@@ -499,28 +756,28 @@ module ActiveRecord
|
|
|
499
756
|
self.class.connection_handler
|
|
500
757
|
end
|
|
501
758
|
|
|
502
|
-
# Returns the
|
|
759
|
+
# Returns the attributes of the record as a nicely formatted string.
|
|
760
|
+
#
|
|
761
|
+
# Post.first.inspect
|
|
762
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
|
763
|
+
#
|
|
764
|
+
# The attributes can be limited by setting <tt>.attributes_for_inspect</tt>.
|
|
765
|
+
#
|
|
766
|
+
# Post.attributes_for_inspect = [:id, :title]
|
|
767
|
+
# Post.first.inspect
|
|
768
|
+
# #=> "#<Post id: 1, title: "Hello, World!">"
|
|
503
769
|
def inspect
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
inspection = if defined?(@attributes) && @attributes
|
|
507
|
-
self.class.attribute_names.collect do |name|
|
|
508
|
-
if has_attribute?(name)
|
|
509
|
-
attr = _read_attribute(name)
|
|
510
|
-
value = if attr.nil?
|
|
511
|
-
attr.inspect
|
|
512
|
-
else
|
|
513
|
-
attr = format_for_inspect(attr)
|
|
514
|
-
inspection_filter.filter_param(name, attr)
|
|
515
|
-
end
|
|
516
|
-
"#{name}: #{value}"
|
|
517
|
-
end
|
|
518
|
-
end.compact.join(", ")
|
|
519
|
-
else
|
|
520
|
-
"not initialized"
|
|
521
|
-
end
|
|
770
|
+
inspect_with_attributes(attributes_for_inspect)
|
|
771
|
+
end
|
|
522
772
|
|
|
523
|
-
|
|
773
|
+
# Returns all attributes of the record as a nicely formatted string,
|
|
774
|
+
# ignoring <tt>.attributes_for_inspect</tt>.
|
|
775
|
+
#
|
|
776
|
+
# Post.first.full_inspect
|
|
777
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
|
778
|
+
#
|
|
779
|
+
def full_inspect
|
|
780
|
+
inspect_with_attributes(all_attributes_for_inspect)
|
|
524
781
|
end
|
|
525
782
|
|
|
526
783
|
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
|
|
@@ -528,17 +785,17 @@ module ActiveRecord
|
|
|
528
785
|
def pretty_print(pp)
|
|
529
786
|
return super if custom_inspect_method_defined?
|
|
530
787
|
pp.object_address_group(self) do
|
|
531
|
-
if
|
|
532
|
-
attr_names =
|
|
788
|
+
if @attributes
|
|
789
|
+
attr_names = attributes_for_inspect.select { |name| _has_attribute?(name.to_s) }
|
|
533
790
|
pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
|
|
791
|
+
attr_name = attr_name.to_s
|
|
534
792
|
pp.breakable " "
|
|
535
793
|
pp.group(1) do
|
|
536
794
|
pp.text attr_name
|
|
537
795
|
pp.text ":"
|
|
538
796
|
pp.breakable
|
|
539
|
-
value =
|
|
540
|
-
|
|
541
|
-
pp.pp value
|
|
797
|
+
value = attribute_for_inspect(attr_name)
|
|
798
|
+
pp.text value
|
|
542
799
|
end
|
|
543
800
|
end
|
|
544
801
|
else
|
|
@@ -548,13 +805,7 @@ module ActiveRecord
|
|
|
548
805
|
end
|
|
549
806
|
end
|
|
550
807
|
|
|
551
|
-
# Returns a hash of the given methods with their names as keys and returned values as values.
|
|
552
|
-
def slice(*methods)
|
|
553
|
-
Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
|
|
554
|
-
end
|
|
555
|
-
|
|
556
808
|
private
|
|
557
|
-
|
|
558
809
|
# +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
|
|
559
810
|
# the array, and then rescues from the possible +NoMethodError+. If those elements are
|
|
560
811
|
# +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
|
|
@@ -568,15 +819,20 @@ module ActiveRecord
|
|
|
568
819
|
end
|
|
569
820
|
|
|
570
821
|
def init_internals
|
|
571
|
-
@primary_key = self.class.primary_key
|
|
572
822
|
@readonly = false
|
|
823
|
+
@previously_new_record = false
|
|
573
824
|
@destroyed = false
|
|
574
825
|
@marked_for_destruction = false
|
|
575
826
|
@destroyed_by_association = nil
|
|
576
827
|
@_start_transaction_state = nil
|
|
577
|
-
@transaction_state = nil
|
|
578
828
|
|
|
579
|
-
self.class
|
|
829
|
+
klass = self.class
|
|
830
|
+
|
|
831
|
+
@primary_key = klass.primary_key
|
|
832
|
+
@strict_loading = klass.strict_loading_by_default
|
|
833
|
+
@strict_loading_mode = :all
|
|
834
|
+
|
|
835
|
+
klass.define_attribute_methods
|
|
580
836
|
end
|
|
581
837
|
|
|
582
838
|
def initialize_internals_callback
|
|
@@ -586,14 +842,40 @@ module ActiveRecord
|
|
|
586
842
|
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
|
587
843
|
end
|
|
588
844
|
|
|
845
|
+
class InspectionMask < DelegateClass(::String)
|
|
846
|
+
def pretty_print(pp)
|
|
847
|
+
pp.text __getobj__
|
|
848
|
+
end
|
|
849
|
+
end
|
|
850
|
+
private_constant :InspectionMask
|
|
851
|
+
|
|
589
852
|
def inspection_filter
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
853
|
+
self.class.inspection_filter
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
def inspect_with_attributes(attributes_to_list)
|
|
857
|
+
inspection = if @attributes
|
|
858
|
+
attributes_to_list.filter_map do |name|
|
|
859
|
+
name = name.to_s
|
|
860
|
+
if _has_attribute?(name)
|
|
861
|
+
"#{name}: #{attribute_for_inspect(name)}"
|
|
862
|
+
end
|
|
863
|
+
end.join(", ")
|
|
864
|
+
else
|
|
865
|
+
"not initialized"
|
|
596
866
|
end
|
|
867
|
+
|
|
868
|
+
"#<#{self.class} #{inspection}>"
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
def attributes_for_inspect
|
|
872
|
+
self.class.attributes_for_inspect == :all ? all_attributes_for_inspect : self.class.attributes_for_inspect
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
def all_attributes_for_inspect
|
|
876
|
+
return [] unless @attributes
|
|
877
|
+
|
|
878
|
+
attribute_names
|
|
597
879
|
end
|
|
598
880
|
end
|
|
599
881
|
end
|