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
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/core_ext/string/filters"
|
|
4
|
-
require "concurrent/map"
|
|
5
4
|
|
|
6
5
|
module ActiveRecord
|
|
7
6
|
# = Active Record Reflection
|
|
@@ -11,6 +10,8 @@ module ActiveRecord
|
|
|
11
10
|
included do
|
|
12
11
|
class_attribute :_reflections, instance_writer: false, default: {}
|
|
13
12
|
class_attribute :aggregate_reflections, instance_writer: false, default: {}
|
|
13
|
+
class_attribute :automatic_scope_inversing, instance_writer: false, default: false
|
|
14
|
+
class_attribute :automatically_invert_plural_associations, instance_writer: false, default: false
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
class << self
|
|
@@ -21,12 +22,12 @@ module ActiveRecord
|
|
|
21
22
|
|
|
22
23
|
def add_reflection(ar, name, reflection)
|
|
23
24
|
ar.clear_reflections_cache
|
|
24
|
-
name =
|
|
25
|
+
name = name.to_sym
|
|
25
26
|
ar._reflections = ar._reflections.except(name).merge!(name => reflection)
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def add_aggregate_reflection(ar, name, reflection)
|
|
29
|
-
ar.aggregate_reflections = ar.aggregate_reflections.merge(
|
|
30
|
+
ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_sym => reflection)
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
private
|
|
@@ -46,6 +47,8 @@ module ActiveRecord
|
|
|
46
47
|
end
|
|
47
48
|
end
|
|
48
49
|
|
|
50
|
+
# = Active Record Reflection
|
|
51
|
+
#
|
|
49
52
|
# \Reflection enables the ability to examine the associations and aggregations of
|
|
50
53
|
# Active Record classes and objects. This information, for example,
|
|
51
54
|
# can be used in a form builder that takes an Active Record object
|
|
@@ -65,7 +68,7 @@ module ActiveRecord
|
|
|
65
68
|
# Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
|
|
66
69
|
#
|
|
67
70
|
def reflect_on_aggregation(aggregation)
|
|
68
|
-
aggregate_reflections[aggregation.
|
|
71
|
+
aggregate_reflections[aggregation.to_sym]
|
|
69
72
|
end
|
|
70
73
|
|
|
71
74
|
# Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
|
|
@@ -73,6 +76,10 @@ module ActiveRecord
|
|
|
73
76
|
# Account.reflections # => {"balance" => AggregateReflection}
|
|
74
77
|
#
|
|
75
78
|
def reflections
|
|
79
|
+
normalized_reflections.stringify_keys
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def normalized_reflections # :nodoc:
|
|
76
83
|
@__reflections ||= begin
|
|
77
84
|
ref = {}
|
|
78
85
|
|
|
@@ -81,13 +88,13 @@ module ActiveRecord
|
|
|
81
88
|
|
|
82
89
|
if parent_reflection
|
|
83
90
|
parent_name = parent_reflection.name
|
|
84
|
-
ref[parent_name
|
|
91
|
+
ref[parent_name] = parent_reflection
|
|
85
92
|
else
|
|
86
93
|
ref[name] = reflection
|
|
87
94
|
end
|
|
88
95
|
end
|
|
89
96
|
|
|
90
|
-
ref
|
|
97
|
+
ref.freeze
|
|
91
98
|
end
|
|
92
99
|
end
|
|
93
100
|
|
|
@@ -102,7 +109,7 @@ module ActiveRecord
|
|
|
102
109
|
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
|
|
103
110
|
#
|
|
104
111
|
def reflect_on_all_associations(macro = nil)
|
|
105
|
-
association_reflections =
|
|
112
|
+
association_reflections = normalized_reflections.values
|
|
106
113
|
association_reflections.select! { |reflection| reflection.macro == macro } if macro
|
|
107
114
|
association_reflections
|
|
108
115
|
end
|
|
@@ -113,21 +120,31 @@ module ActiveRecord
|
|
|
113
120
|
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
|
114
121
|
#
|
|
115
122
|
def reflect_on_association(association)
|
|
116
|
-
|
|
123
|
+
normalized_reflections[association.to_sym]
|
|
117
124
|
end
|
|
118
125
|
|
|
119
|
-
def _reflect_on_association(association)
|
|
120
|
-
_reflections[association.
|
|
126
|
+
def _reflect_on_association(association) # :nodoc:
|
|
127
|
+
_reflections[association.to_sym]
|
|
121
128
|
end
|
|
122
129
|
|
|
123
130
|
# Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
|
|
124
131
|
def reflect_on_all_autosave_associations
|
|
125
|
-
reflections
|
|
132
|
+
reflections = normalized_reflections.values
|
|
133
|
+
reflections.select! { |reflection| reflection.options[:autosave] }
|
|
134
|
+
reflections
|
|
126
135
|
end
|
|
127
136
|
|
|
128
137
|
def clear_reflections_cache # :nodoc:
|
|
129
138
|
@__reflections = nil
|
|
130
139
|
end
|
|
140
|
+
|
|
141
|
+
private
|
|
142
|
+
def inherited(subclass)
|
|
143
|
+
super
|
|
144
|
+
subclass.class_eval do
|
|
145
|
+
@__reflections = nil
|
|
146
|
+
end
|
|
147
|
+
end
|
|
131
148
|
end
|
|
132
149
|
|
|
133
150
|
# Holds all the methods that are shared between MacroReflection and ThroughReflection.
|
|
@@ -144,6 +161,14 @@ module ActiveRecord
|
|
|
144
161
|
# PolymorphicReflection
|
|
145
162
|
# RuntimeReflection
|
|
146
163
|
class AbstractReflection # :nodoc:
|
|
164
|
+
def initialize
|
|
165
|
+
@class_name = nil
|
|
166
|
+
@counter_cache_column = nil
|
|
167
|
+
@inverse_of = nil
|
|
168
|
+
@inverse_which_updates_counter_cache_defined = false
|
|
169
|
+
@inverse_which_updates_counter_cache = nil
|
|
170
|
+
end
|
|
171
|
+
|
|
147
172
|
def through_reflection?
|
|
148
173
|
false
|
|
149
174
|
end
|
|
@@ -163,13 +188,7 @@ module ActiveRecord
|
|
|
163
188
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
|
164
189
|
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
|
165
190
|
def class_name
|
|
166
|
-
@class_name ||= (options[:class_name] || derive_class_name).to_s
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
|
170
|
-
|
|
171
|
-
def join_keys
|
|
172
|
-
@join_keys ||= get_join_keys(klass)
|
|
191
|
+
@class_name ||= -(options[:class_name] || derive_class_name).to_s
|
|
173
192
|
end
|
|
174
193
|
|
|
175
194
|
# Returns a list of scopes that should be applied for this Reflection
|
|
@@ -183,25 +202,31 @@ module ActiveRecord
|
|
|
183
202
|
scope_chain_items = join_scopes(table, predicate_builder)
|
|
184
203
|
klass_scope = klass_join_scope(table, predicate_builder)
|
|
185
204
|
|
|
186
|
-
key = join_keys.key
|
|
187
|
-
foreign_key = join_keys.foreign_key
|
|
188
|
-
|
|
189
|
-
klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
|
|
190
|
-
|
|
191
205
|
if type
|
|
192
206
|
klass_scope.where!(type => foreign_klass.polymorphic_name)
|
|
193
207
|
end
|
|
194
208
|
|
|
209
|
+
scope_chain_items.inject(klass_scope, &:merge!)
|
|
210
|
+
|
|
211
|
+
primary_key_column_names = Array(join_primary_key)
|
|
212
|
+
foreign_key_column_names = Array(join_foreign_key)
|
|
213
|
+
|
|
214
|
+
primary_foreign_key_pairs = primary_key_column_names.zip(foreign_key_column_names)
|
|
215
|
+
|
|
216
|
+
primary_foreign_key_pairs.each do |primary_key_column_name, foreign_key_column_name|
|
|
217
|
+
klass_scope.where!(table[primary_key_column_name].eq(foreign_table[foreign_key_column_name]))
|
|
218
|
+
end
|
|
219
|
+
|
|
195
220
|
if klass.finder_needs_type_condition?
|
|
196
221
|
klass_scope.where!(klass.send(:type_condition, table))
|
|
197
222
|
end
|
|
198
223
|
|
|
199
|
-
|
|
224
|
+
klass_scope
|
|
200
225
|
end
|
|
201
226
|
|
|
202
|
-
def join_scopes(table, predicate_builder) # :nodoc:
|
|
227
|
+
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
|
203
228
|
if scope
|
|
204
|
-
[scope_for(build_scope(table, predicate_builder))]
|
|
229
|
+
[scope_for(build_scope(table, predicate_builder, klass), record)]
|
|
205
230
|
else
|
|
206
231
|
[]
|
|
207
232
|
end
|
|
@@ -217,14 +242,16 @@ module ActiveRecord
|
|
|
217
242
|
end
|
|
218
243
|
|
|
219
244
|
def counter_cache_column
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
245
|
+
@counter_cache_column ||= begin
|
|
246
|
+
counter_cache = options[:counter_cache]
|
|
247
|
+
|
|
248
|
+
if belongs_to?
|
|
249
|
+
if counter_cache
|
|
250
|
+
counter_cache[:column] || -"#{active_record.name.demodulize.underscore.pluralize}_count"
|
|
251
|
+
end
|
|
252
|
+
else
|
|
253
|
+
-((counter_cache && -counter_cache[:column]) || "#{name}_count")
|
|
225
254
|
end
|
|
226
|
-
else
|
|
227
|
-
options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
|
|
228
255
|
end
|
|
229
256
|
end
|
|
230
257
|
|
|
@@ -235,14 +262,17 @@ module ActiveRecord
|
|
|
235
262
|
end
|
|
236
263
|
|
|
237
264
|
def check_validity_of_inverse!
|
|
238
|
-
|
|
239
|
-
if
|
|
265
|
+
if !polymorphic? && has_inverse?
|
|
266
|
+
if inverse_of.nil?
|
|
240
267
|
raise InverseOfAssociationNotFoundError.new(self)
|
|
241
268
|
end
|
|
269
|
+
if inverse_of == self
|
|
270
|
+
raise InverseOfAssociationRecursiveError.new(self)
|
|
271
|
+
end
|
|
242
272
|
end
|
|
243
273
|
end
|
|
244
274
|
|
|
245
|
-
#
|
|
275
|
+
# We need to avoid the following situation:
|
|
246
276
|
#
|
|
247
277
|
# * An associated record is deleted via record.destroy
|
|
248
278
|
# * Hence the callbacks run, and they find a belongs_to on the record with a
|
|
@@ -253,10 +283,16 @@ module ActiveRecord
|
|
|
253
283
|
#
|
|
254
284
|
# Hence this method.
|
|
255
285
|
def inverse_which_updates_counter_cache
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
286
|
+
unless @inverse_which_updates_counter_cache_defined
|
|
287
|
+
if counter_cache_column
|
|
288
|
+
inverse_candidates = inverse_of ? [inverse_of] : klass.reflect_on_all_associations(:belongs_to)
|
|
289
|
+
@inverse_which_updates_counter_cache = inverse_candidates.find do |inverse|
|
|
290
|
+
inverse.counter_cache_column == counter_cache_column && (inverse.polymorphic? || inverse.klass == active_record)
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
@inverse_which_updates_counter_cache_defined = true
|
|
259
294
|
end
|
|
295
|
+
@inverse_which_updates_counter_cache
|
|
260
296
|
end
|
|
261
297
|
alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
|
|
262
298
|
|
|
@@ -264,14 +300,25 @@ module ActiveRecord
|
|
|
264
300
|
inverse_of && inverse_which_updates_counter_cache == inverse_of
|
|
265
301
|
end
|
|
266
302
|
|
|
267
|
-
# Returns whether a counter cache
|
|
303
|
+
# Returns whether this association has a counter cache.
|
|
268
304
|
#
|
|
269
305
|
# The counter_cache option must be given on either the owner or inverse
|
|
270
306
|
# association, and the column must be present on the owner.
|
|
271
307
|
def has_cached_counter?
|
|
272
308
|
options[:counter_cache] ||
|
|
273
309
|
inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
|
|
274
|
-
|
|
310
|
+
active_record.has_attribute?(counter_cache_column)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Returns whether this association has a counter cache and its column values were backfilled
|
|
314
|
+
# (and so it is used internally by methods like +size+/+any?+/etc).
|
|
315
|
+
def has_active_cached_counter?
|
|
316
|
+
return false unless has_cached_counter?
|
|
317
|
+
|
|
318
|
+
counter_cache = options[:counter_cache] ||
|
|
319
|
+
(inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache])
|
|
320
|
+
|
|
321
|
+
counter_cache[:active] != false
|
|
275
322
|
end
|
|
276
323
|
|
|
277
324
|
def counter_must_be_updated_by_has_many?
|
|
@@ -286,11 +333,7 @@ module ActiveRecord
|
|
|
286
333
|
collect_join_chain
|
|
287
334
|
end
|
|
288
335
|
|
|
289
|
-
def
|
|
290
|
-
JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
def build_scope(table, predicate_builder = predicate_builder(table))
|
|
336
|
+
def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
|
|
294
337
|
Relation.create(
|
|
295
338
|
klass,
|
|
296
339
|
table: table,
|
|
@@ -298,12 +341,14 @@ module ActiveRecord
|
|
|
298
341
|
)
|
|
299
342
|
end
|
|
300
343
|
|
|
301
|
-
def
|
|
302
|
-
|
|
344
|
+
def strict_loading?
|
|
345
|
+
options[:strict_loading]
|
|
303
346
|
end
|
|
304
347
|
|
|
305
|
-
def
|
|
306
|
-
|
|
348
|
+
def strict_loading_violation_message(owner)
|
|
349
|
+
message = +"`#{owner}` is marked for strict_loading."
|
|
350
|
+
message << " The #{polymorphic? ? "polymorphic association" : "#{klass} association"}"
|
|
351
|
+
message << " named `:#{name}` cannot be lazily loaded."
|
|
307
352
|
end
|
|
308
353
|
|
|
309
354
|
protected
|
|
@@ -319,6 +364,12 @@ module ActiveRecord
|
|
|
319
364
|
def primary_key(klass)
|
|
320
365
|
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
|
321
366
|
end
|
|
367
|
+
|
|
368
|
+
def ensure_option_not_given_as_class!(option_name)
|
|
369
|
+
if options[option_name] && options[option_name].class == Class
|
|
370
|
+
raise ArgumentError, "A class was passed to `:#{option_name}` but we are expecting a string."
|
|
371
|
+
end
|
|
372
|
+
end
|
|
322
373
|
end
|
|
323
374
|
|
|
324
375
|
# Base class for AggregateReflection and AssociationReflection. Objects of
|
|
@@ -343,9 +394,10 @@ module ActiveRecord
|
|
|
343
394
|
attr_reader :plural_name # :nodoc:
|
|
344
395
|
|
|
345
396
|
def initialize(name, scope, options, active_record)
|
|
397
|
+
super()
|
|
346
398
|
@name = name
|
|
347
399
|
@scope = scope
|
|
348
|
-
@options = options
|
|
400
|
+
@options = normalize_options(options)
|
|
349
401
|
@active_record = active_record
|
|
350
402
|
@klass = options[:anonymous_class]
|
|
351
403
|
@plural_name = active_record.pluralize_table_names ?
|
|
@@ -376,7 +428,15 @@ module ActiveRecord
|
|
|
376
428
|
# a new association object. Use +build_association+ or +create_association+
|
|
377
429
|
# instead. This allows plugins to hook into association object creation.
|
|
378
430
|
def klass
|
|
379
|
-
@klass ||=
|
|
431
|
+
@klass ||= _klass(class_name)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def _klass(class_name) # :nodoc:
|
|
435
|
+
if active_record.name.demodulize == class_name
|
|
436
|
+
return compute_class("::#{class_name}") rescue NameError
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
compute_class(class_name)
|
|
380
440
|
end
|
|
381
441
|
|
|
382
442
|
def compute_class(name)
|
|
@@ -401,11 +461,31 @@ module ActiveRecord
|
|
|
401
461
|
def derive_class_name
|
|
402
462
|
name.to_s.camelize
|
|
403
463
|
end
|
|
464
|
+
|
|
465
|
+
def normalize_options(options)
|
|
466
|
+
counter_cache = options.delete(:counter_cache)
|
|
467
|
+
|
|
468
|
+
if counter_cache
|
|
469
|
+
active = true
|
|
470
|
+
|
|
471
|
+
case counter_cache
|
|
472
|
+
when String, Symbol
|
|
473
|
+
column = -counter_cache.to_s
|
|
474
|
+
when Hash
|
|
475
|
+
active = counter_cache.fetch(:active, true)
|
|
476
|
+
column = counter_cache[:column]&.to_s
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
options[:counter_cache] = { active: active, column: column }
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
options
|
|
483
|
+
end
|
|
404
484
|
end
|
|
405
485
|
|
|
406
486
|
# Holds all the metadata about an aggregation as it was specified in the
|
|
407
487
|
# Active Record class.
|
|
408
|
-
class AggregateReflection < MacroReflection
|
|
488
|
+
class AggregateReflection < MacroReflection # :nodoc:
|
|
409
489
|
def mapping
|
|
410
490
|
mapping = options[:mapping] || [name, name]
|
|
411
491
|
mapping.first.is_a?(Array) ? mapping : [mapping]
|
|
@@ -414,12 +494,29 @@ module ActiveRecord
|
|
|
414
494
|
|
|
415
495
|
# Holds all the metadata about an association as it was specified in the
|
|
416
496
|
# Active Record class.
|
|
417
|
-
class AssociationReflection < MacroReflection
|
|
497
|
+
class AssociationReflection < MacroReflection # :nodoc:
|
|
418
498
|
def compute_class(name)
|
|
419
499
|
if polymorphic?
|
|
420
500
|
raise ArgumentError, "Polymorphic associations do not support computing the class."
|
|
421
501
|
end
|
|
422
|
-
|
|
502
|
+
|
|
503
|
+
begin
|
|
504
|
+
klass = active_record.send(:compute_type, name)
|
|
505
|
+
rescue NameError => error
|
|
506
|
+
if error.name.match?(/(?:\A|::)#{name}\z/)
|
|
507
|
+
message = "Missing model class #{name} for the #{active_record}##{self.name} association."
|
|
508
|
+
message += " You can specify a different model class with the :class_name option." unless options[:class_name]
|
|
509
|
+
raise NameError.new(message, name)
|
|
510
|
+
else
|
|
511
|
+
raise
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
unless klass < ActiveRecord::Base
|
|
516
|
+
raise ArgumentError, "The #{name} model class for the #{active_record}##{self.name} association is not an ActiveRecord::Base subclass."
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
klass
|
|
423
520
|
end
|
|
424
521
|
|
|
425
522
|
attr_reader :type, :foreign_type
|
|
@@ -427,68 +524,126 @@ module ActiveRecord
|
|
|
427
524
|
|
|
428
525
|
def initialize(name, scope, options, active_record)
|
|
429
526
|
super
|
|
430
|
-
@type
|
|
431
|
-
@foreign_type =
|
|
432
|
-
@
|
|
433
|
-
@
|
|
527
|
+
@type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
|
|
528
|
+
@foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
|
|
529
|
+
@join_table = nil
|
|
530
|
+
@foreign_key = nil
|
|
531
|
+
@association_foreign_key = nil
|
|
532
|
+
@association_primary_key = nil
|
|
533
|
+
if options[:query_constraints]
|
|
534
|
+
ActiveRecord.deprecator.warn <<~MSG.squish
|
|
535
|
+
Setting `query_constraints:` option on `#{active_record}.#{macro} :#{name}` is deprecated.
|
|
536
|
+
To maintain current behavior, use the `foreign_key` option instead.
|
|
537
|
+
MSG
|
|
538
|
+
end
|
|
434
539
|
|
|
435
|
-
|
|
436
|
-
|
|
540
|
+
# If the foreign key is an array, set query constraints options and don't use the foreign key
|
|
541
|
+
if options[:foreign_key].is_a?(Array)
|
|
542
|
+
options[:query_constraints] = options.delete(:foreign_key)
|
|
437
543
|
end
|
|
544
|
+
|
|
545
|
+
ensure_option_not_given_as_class!(:class_name)
|
|
438
546
|
end
|
|
439
547
|
|
|
440
|
-
def association_scope_cache(
|
|
441
|
-
key =
|
|
548
|
+
def association_scope_cache(klass, owner, &block)
|
|
549
|
+
key = self
|
|
442
550
|
if polymorphic?
|
|
443
551
|
key = [key, owner._read_attribute(@foreign_type)]
|
|
444
552
|
end
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
def constructable? # :nodoc:
|
|
449
|
-
@constructable
|
|
553
|
+
klass.with_connection do |connection|
|
|
554
|
+
klass.cached_find_by_statement(connection, key, &block)
|
|
555
|
+
end
|
|
450
556
|
end
|
|
451
557
|
|
|
452
558
|
def join_table
|
|
453
|
-
@join_table ||= options[:join_table] || derive_join_table
|
|
559
|
+
@join_table ||= -(options[:join_table]&.to_s || derive_join_table)
|
|
454
560
|
end
|
|
455
561
|
|
|
456
|
-
def foreign_key
|
|
457
|
-
@foreign_key ||= options[:foreign_key]
|
|
562
|
+
def foreign_key(infer_from_inverse_of: true)
|
|
563
|
+
@foreign_key ||= if options[:foreign_key]
|
|
564
|
+
if options[:foreign_key].is_a?(Array)
|
|
565
|
+
options[:foreign_key].map { |fk| fk.to_s.freeze }.freeze
|
|
566
|
+
else
|
|
567
|
+
options[:foreign_key].to_s.freeze
|
|
568
|
+
end
|
|
569
|
+
elsif options[:query_constraints]
|
|
570
|
+
options[:query_constraints].map { |fk| fk.to_s.freeze }.freeze
|
|
571
|
+
else
|
|
572
|
+
derived_fk = derive_foreign_key(infer_from_inverse_of: infer_from_inverse_of)
|
|
573
|
+
|
|
574
|
+
if active_record.has_query_constraints?
|
|
575
|
+
derived_fk = derive_fk_query_constraints(derived_fk)
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
derived_fk
|
|
579
|
+
end
|
|
458
580
|
end
|
|
459
581
|
|
|
460
582
|
def association_foreign_key
|
|
461
|
-
@association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
|
|
583
|
+
@association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
|
|
462
584
|
end
|
|
463
585
|
|
|
464
|
-
# klass option is necessary to support loading polymorphic associations
|
|
465
586
|
def association_primary_key(klass = nil)
|
|
466
|
-
|
|
587
|
+
primary_key(klass || self.klass)
|
|
467
588
|
end
|
|
468
589
|
|
|
469
590
|
def active_record_primary_key
|
|
470
|
-
|
|
591
|
+
custom_primary_key = options[:primary_key]
|
|
592
|
+
@active_record_primary_key ||= if custom_primary_key
|
|
593
|
+
if custom_primary_key.is_a?(Array)
|
|
594
|
+
custom_primary_key.map { |pk| pk.to_s.freeze }.freeze
|
|
595
|
+
else
|
|
596
|
+
custom_primary_key.to_s.freeze
|
|
597
|
+
end
|
|
598
|
+
elsif active_record.has_query_constraints? || options[:query_constraints]
|
|
599
|
+
active_record.query_constraints_list
|
|
600
|
+
elsif active_record.composite_primary_key?
|
|
601
|
+
# If active_record has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
|
|
602
|
+
primary_key = primary_key(active_record)
|
|
603
|
+
primary_key.include?("id") ? "id" : primary_key.freeze
|
|
604
|
+
else
|
|
605
|
+
primary_key(active_record).freeze
|
|
606
|
+
end
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
def join_primary_key(klass = nil)
|
|
610
|
+
foreign_key
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
def join_primary_type
|
|
614
|
+
type
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def join_foreign_key
|
|
618
|
+
active_record_primary_key
|
|
471
619
|
end
|
|
472
620
|
|
|
473
621
|
def check_validity!
|
|
474
622
|
check_validity_of_inverse!
|
|
623
|
+
|
|
624
|
+
if !polymorphic? && (klass.composite_primary_key? || active_record.composite_primary_key?)
|
|
625
|
+
if (has_one? || collection?) && Array(active_record_primary_key).length != Array(foreign_key).length
|
|
626
|
+
raise CompositePrimaryKeyMismatchError.new(self)
|
|
627
|
+
elsif belongs_to? && Array(association_primary_key).length != Array(foreign_key).length
|
|
628
|
+
raise CompositePrimaryKeyMismatchError.new(self)
|
|
629
|
+
end
|
|
630
|
+
end
|
|
475
631
|
end
|
|
476
632
|
|
|
477
|
-
def
|
|
633
|
+
def check_eager_loadable!
|
|
478
634
|
return unless scope
|
|
479
635
|
|
|
480
636
|
unless scope.arity == 0
|
|
481
637
|
raise ArgumentError, <<-MSG.squish
|
|
482
638
|
The association scope '#{name}' is instance dependent (the scope
|
|
483
|
-
block takes an argument).
|
|
484
|
-
not supported.
|
|
639
|
+
block takes an argument). Eager loading instance dependent scopes
|
|
640
|
+
is not supported.
|
|
485
641
|
MSG
|
|
486
642
|
end
|
|
487
643
|
end
|
|
488
|
-
alias :check_eager_loadable! :check_preloadable!
|
|
489
644
|
|
|
490
645
|
def join_id_for(owner) # :nodoc:
|
|
491
|
-
owner
|
|
646
|
+
Array(join_foreign_key).map { |key| owner._read_attribute(key) }
|
|
492
647
|
end
|
|
493
648
|
|
|
494
649
|
def through_reflection
|
|
@@ -508,7 +663,7 @@ module ActiveRecord
|
|
|
508
663
|
# This is for clearing cache on the reflection. Useful for tests that need to compare
|
|
509
664
|
# SQL queries on associations.
|
|
510
665
|
def clear_association_scope_cache # :nodoc:
|
|
511
|
-
|
|
666
|
+
klass.initialize_find_by_cache
|
|
512
667
|
end
|
|
513
668
|
|
|
514
669
|
def nested?
|
|
@@ -570,8 +725,9 @@ module ActiveRecord
|
|
|
570
725
|
options[:polymorphic]
|
|
571
726
|
end
|
|
572
727
|
|
|
573
|
-
|
|
574
|
-
|
|
728
|
+
def polymorphic_name
|
|
729
|
+
active_record.polymorphic_name
|
|
730
|
+
end
|
|
575
731
|
|
|
576
732
|
def add_as_source(seed)
|
|
577
733
|
seed
|
|
@@ -590,11 +746,6 @@ module ActiveRecord
|
|
|
590
746
|
end
|
|
591
747
|
|
|
592
748
|
private
|
|
593
|
-
|
|
594
|
-
def calculate_constructable(macro, options)
|
|
595
|
-
true
|
|
596
|
-
end
|
|
597
|
-
|
|
598
749
|
# Attempts to find the inverse association name automatically.
|
|
599
750
|
# If it cannot find a suitable inverse association name, it returns
|
|
600
751
|
# +nil+.
|
|
@@ -613,14 +764,20 @@ module ActiveRecord
|
|
|
613
764
|
|
|
614
765
|
begin
|
|
615
766
|
reflection = klass._reflect_on_association(inverse_name)
|
|
616
|
-
|
|
767
|
+
if !reflection && active_record.automatically_invert_plural_associations
|
|
768
|
+
plural_inverse_name = ActiveSupport::Inflector.pluralize(inverse_name)
|
|
769
|
+
reflection = klass._reflect_on_association(plural_inverse_name)
|
|
770
|
+
end
|
|
771
|
+
rescue NameError => error
|
|
772
|
+
raise unless error.name.to_s == class_name
|
|
773
|
+
|
|
617
774
|
# Give up: we couldn't compute the klass type so we won't be able
|
|
618
775
|
# to find any associations either.
|
|
619
776
|
reflection = false
|
|
620
777
|
end
|
|
621
778
|
|
|
622
779
|
if valid_inverse_reflection?(reflection)
|
|
623
|
-
|
|
780
|
+
reflection.name
|
|
624
781
|
end
|
|
625
782
|
end
|
|
626
783
|
end
|
|
@@ -631,8 +788,10 @@ module ActiveRecord
|
|
|
631
788
|
# with the current reflection's klass name.
|
|
632
789
|
def valid_inverse_reflection?(reflection)
|
|
633
790
|
reflection &&
|
|
791
|
+
reflection != self &&
|
|
792
|
+
foreign_key == reflection.foreign_key &&
|
|
634
793
|
klass <= reflection.active_record &&
|
|
635
|
-
can_find_inverse_of_automatically?(reflection)
|
|
794
|
+
can_find_inverse_of_automatically?(reflection, true)
|
|
636
795
|
end
|
|
637
796
|
|
|
638
797
|
# Checks to see if the reflection doesn't have any options that prevent
|
|
@@ -641,14 +800,25 @@ module ActiveRecord
|
|
|
641
800
|
# have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
|
|
642
801
|
# Third, we must not have options such as <tt>:foreign_key</tt>
|
|
643
802
|
# which prevent us from correctly guessing the inverse association.
|
|
644
|
-
|
|
645
|
-
# Anything with a scope can additionally ruin our attempt at finding an
|
|
646
|
-
# inverse, so we exclude reflections with scopes.
|
|
647
|
-
def can_find_inverse_of_automatically?(reflection)
|
|
803
|
+
def can_find_inverse_of_automatically?(reflection, inverse_reflection = false)
|
|
648
804
|
reflection.options[:inverse_of] != false &&
|
|
649
|
-
|
|
650
|
-
!
|
|
805
|
+
!reflection.options[:through] &&
|
|
806
|
+
!reflection.options[:foreign_key] &&
|
|
807
|
+
scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
# Scopes on the potential inverse reflection prevent automatic
|
|
811
|
+
# <tt>inverse_of</tt>, since the scope could exclude the owner record
|
|
812
|
+
# we would inverse from. Scopes on the reflection itself allow for
|
|
813
|
+
# automatic <tt>inverse_of</tt> as long as
|
|
814
|
+
# <tt>config.active_record.automatic_scope_inversing<tt> is set to
|
|
815
|
+
# +true+ (the default for new applications).
|
|
816
|
+
def scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
|
|
817
|
+
if inverse_reflection
|
|
651
818
|
!reflection.scope
|
|
819
|
+
else
|
|
820
|
+
!reflection.scope || reflection.klass.automatic_scope_inversing
|
|
821
|
+
end
|
|
652
822
|
end
|
|
653
823
|
|
|
654
824
|
def derive_class_name
|
|
@@ -657,13 +827,55 @@ module ActiveRecord
|
|
|
657
827
|
class_name.camelize
|
|
658
828
|
end
|
|
659
829
|
|
|
660
|
-
def derive_foreign_key
|
|
830
|
+
def derive_foreign_key(infer_from_inverse_of: true)
|
|
661
831
|
if belongs_to?
|
|
662
832
|
"#{name}_id"
|
|
663
833
|
elsif options[:as]
|
|
664
834
|
"#{options[:as]}_id"
|
|
835
|
+
elsif options[:inverse_of] && infer_from_inverse_of
|
|
836
|
+
inverse_of.foreign_key(infer_from_inverse_of: false)
|
|
665
837
|
else
|
|
666
|
-
active_record.
|
|
838
|
+
active_record.model_name.to_s.foreign_key
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
def derive_fk_query_constraints(foreign_key)
|
|
843
|
+
primary_query_constraints = active_record.query_constraints_list
|
|
844
|
+
owner_pk = active_record.primary_key
|
|
845
|
+
|
|
846
|
+
if primary_query_constraints.size > 2
|
|
847
|
+
raise ArgumentError, <<~MSG.squish
|
|
848
|
+
The query constraints list on the `#{active_record}` model has more than 2
|
|
849
|
+
attributes. Active Record is unable to derive the query constraints
|
|
850
|
+
for the association. You need to explicitly define the query constraints
|
|
851
|
+
for this association.
|
|
852
|
+
MSG
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
if !primary_query_constraints.include?(owner_pk)
|
|
856
|
+
raise ArgumentError, <<~MSG.squish
|
|
857
|
+
The query constraints on the `#{active_record}` model does not include the primary
|
|
858
|
+
key so Active Record is unable to derive the foreign key constraints for
|
|
859
|
+
the association. You need to explicitly define the query constraints for this
|
|
860
|
+
association.
|
|
861
|
+
MSG
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
return foreign_key if primary_query_constraints.include?(foreign_key)
|
|
865
|
+
|
|
866
|
+
first_key, last_key = primary_query_constraints
|
|
867
|
+
|
|
868
|
+
if first_key == owner_pk
|
|
869
|
+
[foreign_key, last_key.to_s]
|
|
870
|
+
elsif last_key == owner_pk
|
|
871
|
+
[first_key.to_s, foreign_key]
|
|
872
|
+
else
|
|
873
|
+
raise ArgumentError, <<~MSG.squish
|
|
874
|
+
Active Record couldn't correctly interpret the query constraints
|
|
875
|
+
for the `#{active_record}` model. The query constraints on `#{active_record}` are
|
|
876
|
+
`#{primary_query_constraints}` and the foreign key is `#{foreign_key}`.
|
|
877
|
+
You need to explicitly set the query constraints for this association.
|
|
878
|
+
MSG
|
|
667
879
|
end
|
|
668
880
|
end
|
|
669
881
|
|
|
@@ -684,10 +896,6 @@ module ActiveRecord
|
|
|
684
896
|
Associations::HasManyAssociation
|
|
685
897
|
end
|
|
686
898
|
end
|
|
687
|
-
|
|
688
|
-
def association_primary_key(klass = nil)
|
|
689
|
-
primary_key(klass || self.klass)
|
|
690
|
-
end
|
|
691
899
|
end
|
|
692
900
|
|
|
693
901
|
class HasOneReflection < AssociationReflection # :nodoc:
|
|
@@ -702,12 +910,6 @@ module ActiveRecord
|
|
|
702
910
|
Associations::HasOneAssociation
|
|
703
911
|
end
|
|
704
912
|
end
|
|
705
|
-
|
|
706
|
-
private
|
|
707
|
-
|
|
708
|
-
def calculate_constructable(macro, options)
|
|
709
|
-
!options[:through]
|
|
710
|
-
end
|
|
711
913
|
end
|
|
712
914
|
|
|
713
915
|
class BelongsToReflection < AssociationReflection # :nodoc:
|
|
@@ -723,6 +925,25 @@ module ActiveRecord
|
|
|
723
925
|
end
|
|
724
926
|
end
|
|
725
927
|
|
|
928
|
+
# klass option is necessary to support loading polymorphic associations
|
|
929
|
+
def association_primary_key(klass = nil)
|
|
930
|
+
if primary_key = options[:primary_key]
|
|
931
|
+
@association_primary_key ||= if primary_key.is_a?(Array)
|
|
932
|
+
primary_key.map { |pk| pk.to_s.freeze }.freeze
|
|
933
|
+
else
|
|
934
|
+
-primary_key.to_s
|
|
935
|
+
end
|
|
936
|
+
elsif (klass || self.klass).has_query_constraints? || options[:query_constraints]
|
|
937
|
+
(klass || self.klass).composite_query_constraints_list
|
|
938
|
+
elsif (klass || self.klass).composite_primary_key?
|
|
939
|
+
# If klass has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
|
|
940
|
+
primary_key = (klass || self.klass).primary_key
|
|
941
|
+
primary_key.include?("id") ? "id" : primary_key
|
|
942
|
+
else
|
|
943
|
+
primary_key(klass || self.klass)
|
|
944
|
+
end
|
|
945
|
+
end
|
|
946
|
+
|
|
726
947
|
def join_primary_key(klass = nil)
|
|
727
948
|
polymorphic? ? association_primary_key(klass) : association_primary_key
|
|
728
949
|
end
|
|
@@ -731,14 +952,14 @@ module ActiveRecord
|
|
|
731
952
|
foreign_key
|
|
732
953
|
end
|
|
733
954
|
|
|
955
|
+
def join_foreign_type
|
|
956
|
+
foreign_type
|
|
957
|
+
end
|
|
958
|
+
|
|
734
959
|
private
|
|
735
|
-
def can_find_inverse_of_automatically?(
|
|
960
|
+
def can_find_inverse_of_automatically?(*)
|
|
736
961
|
!polymorphic? && super
|
|
737
962
|
end
|
|
738
|
-
|
|
739
|
-
def calculate_constructable(macro, options)
|
|
740
|
-
!polymorphic?
|
|
741
|
-
end
|
|
742
963
|
end
|
|
743
964
|
|
|
744
965
|
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
|
|
@@ -751,14 +972,17 @@ module ActiveRecord
|
|
|
751
972
|
|
|
752
973
|
# Holds all the metadata about a :through association as it was specified
|
|
753
974
|
# in the Active Record class.
|
|
754
|
-
class ThroughReflection < AbstractReflection
|
|
755
|
-
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
|
|
756
|
-
:active_record_primary_key, :
|
|
975
|
+
class ThroughReflection < AbstractReflection # :nodoc:
|
|
976
|
+
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
|
|
977
|
+
:active_record_primary_key, :join_foreign_key, to: :source_reflection
|
|
757
978
|
|
|
758
979
|
def initialize(delegate_reflection)
|
|
980
|
+
super()
|
|
759
981
|
@delegate_reflection = delegate_reflection
|
|
760
982
|
@klass = delegate_reflection.options[:anonymous_class]
|
|
761
983
|
@source_reflection_name = delegate_reflection.options[:source]
|
|
984
|
+
|
|
985
|
+
ensure_option_not_given_as_class!(:source_type)
|
|
762
986
|
end
|
|
763
987
|
|
|
764
988
|
def through_reflection?
|
|
@@ -766,7 +990,7 @@ module ActiveRecord
|
|
|
766
990
|
end
|
|
767
991
|
|
|
768
992
|
def klass
|
|
769
|
-
@klass ||= delegate_reflection.
|
|
993
|
+
@klass ||= delegate_reflection._klass(class_name)
|
|
770
994
|
end
|
|
771
995
|
|
|
772
996
|
# Returns the source of the through reflection. It checks both a singularized
|
|
@@ -787,6 +1011,8 @@ module ActiveRecord
|
|
|
787
1011
|
# # => <ActiveRecord::Reflection::BelongsToReflection: @name=:tag, @active_record=Tagging, @plural_name="tags">
|
|
788
1012
|
#
|
|
789
1013
|
def source_reflection
|
|
1014
|
+
return unless source_reflection_name
|
|
1015
|
+
|
|
790
1016
|
through_reflection.klass._reflect_on_association(source_reflection_name)
|
|
791
1017
|
end
|
|
792
1018
|
|
|
@@ -839,8 +1065,8 @@ module ActiveRecord
|
|
|
839
1065
|
source_reflection.scopes + super
|
|
840
1066
|
end
|
|
841
1067
|
|
|
842
|
-
def join_scopes(table, predicate_builder) # :nodoc:
|
|
843
|
-
source_reflection.join_scopes(table, predicate_builder) + super
|
|
1068
|
+
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
|
1069
|
+
source_reflection.join_scopes(table, predicate_builder, klass, record) + super
|
|
844
1070
|
end
|
|
845
1071
|
|
|
846
1072
|
def has_scope?
|
|
@@ -860,7 +1086,15 @@ module ActiveRecord
|
|
|
860
1086
|
def association_primary_key(klass = nil)
|
|
861
1087
|
# Get the "actual" source reflection if the immediate source reflection has a
|
|
862
1088
|
# source reflection itself
|
|
863
|
-
actual_source_reflection.options[:primary_key]
|
|
1089
|
+
if primary_key = actual_source_reflection.options[:primary_key]
|
|
1090
|
+
@association_primary_key ||= -primary_key.to_s
|
|
1091
|
+
else
|
|
1092
|
+
primary_key(klass || self.klass)
|
|
1093
|
+
end
|
|
1094
|
+
end
|
|
1095
|
+
|
|
1096
|
+
def join_primary_key(klass = self.klass)
|
|
1097
|
+
source_reflection.join_primary_key(klass)
|
|
864
1098
|
end
|
|
865
1099
|
|
|
866
1100
|
# Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
|
|
@@ -879,24 +1113,23 @@ module ActiveRecord
|
|
|
879
1113
|
end
|
|
880
1114
|
|
|
881
1115
|
def source_reflection_name # :nodoc:
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1116
|
+
@source_reflection_name ||= begin
|
|
1117
|
+
names = [name.to_s.singularize, name].collect(&:to_sym).uniq
|
|
1118
|
+
names = names.find_all { |n|
|
|
1119
|
+
through_reflection.klass._reflect_on_association(n)
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
if names.length > 1
|
|
1123
|
+
raise AmbiguousSourceReflectionForThroughAssociation.new(
|
|
1124
|
+
active_record.name,
|
|
1125
|
+
macro,
|
|
1126
|
+
name,
|
|
1127
|
+
options,
|
|
1128
|
+
source_reflection_names
|
|
1129
|
+
)
|
|
1130
|
+
end
|
|
1131
|
+
names.first
|
|
897
1132
|
end
|
|
898
|
-
|
|
899
|
-
@source_reflection_name = names.first
|
|
900
1133
|
end
|
|
901
1134
|
|
|
902
1135
|
def source_options
|
|
@@ -909,7 +1142,7 @@ module ActiveRecord
|
|
|
909
1142
|
|
|
910
1143
|
def check_validity!
|
|
911
1144
|
if through_reflection.nil?
|
|
912
|
-
raise HasManyThroughAssociationNotFoundError.new(active_record
|
|
1145
|
+
raise HasManyThroughAssociationNotFoundError.new(active_record, self)
|
|
913
1146
|
end
|
|
914
1147
|
|
|
915
1148
|
if through_reflection.polymorphic?
|
|
@@ -937,7 +1170,7 @@ module ActiveRecord
|
|
|
937
1170
|
end
|
|
938
1171
|
|
|
939
1172
|
if parent_reflection.nil?
|
|
940
|
-
reflections = active_record.
|
|
1173
|
+
reflections = active_record.normalized_reflections.keys
|
|
941
1174
|
|
|
942
1175
|
if reflections.index(through_reflection.name) > reflections.index(name)
|
|
943
1176
|
raise HasManyThroughOrderError.new(active_record.name, self, through_reflection)
|
|
@@ -996,16 +1229,21 @@ module ActiveRecord
|
|
|
996
1229
|
end
|
|
997
1230
|
|
|
998
1231
|
class PolymorphicReflection < AbstractReflection # :nodoc:
|
|
999
|
-
delegate :klass, :scope, :plural_name, :type, :
|
|
1232
|
+
delegate :klass, :scope, :plural_name, :type, :join_primary_key, :join_foreign_key,
|
|
1233
|
+
:name, :scope_for, to: :@reflection
|
|
1000
1234
|
|
|
1001
1235
|
def initialize(reflection, previous_reflection)
|
|
1236
|
+
super()
|
|
1002
1237
|
@reflection = reflection
|
|
1003
1238
|
@previous_reflection = previous_reflection
|
|
1004
1239
|
end
|
|
1005
1240
|
|
|
1006
|
-
def join_scopes(table, predicate_builder) # :nodoc:
|
|
1007
|
-
scopes =
|
|
1008
|
-
|
|
1241
|
+
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
|
1242
|
+
scopes = super
|
|
1243
|
+
unless @previous_reflection.through_reflection?
|
|
1244
|
+
scopes += @previous_reflection.join_scopes(table, predicate_builder, klass, record)
|
|
1245
|
+
end
|
|
1246
|
+
scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
|
|
1009
1247
|
end
|
|
1010
1248
|
|
|
1011
1249
|
def constraints
|
|
@@ -1021,9 +1259,10 @@ module ActiveRecord
|
|
|
1021
1259
|
end
|
|
1022
1260
|
|
|
1023
1261
|
class RuntimeReflection < AbstractReflection # :nodoc:
|
|
1024
|
-
delegate :scope, :type, :constraints, :
|
|
1262
|
+
delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
|
|
1025
1263
|
|
|
1026
1264
|
def initialize(reflection, association)
|
|
1265
|
+
super()
|
|
1027
1266
|
@reflection = reflection
|
|
1028
1267
|
@association = association
|
|
1029
1268
|
end
|
|
@@ -1033,7 +1272,11 @@ module ActiveRecord
|
|
|
1033
1272
|
end
|
|
1034
1273
|
|
|
1035
1274
|
def aliased_table
|
|
1036
|
-
|
|
1275
|
+
klass.arel_table
|
|
1276
|
+
end
|
|
1277
|
+
|
|
1278
|
+
def join_primary_key(klass = self.klass)
|
|
1279
|
+
@reflection.join_primary_key(klass)
|
|
1037
1280
|
end
|
|
1038
1281
|
|
|
1039
1282
|
def all_includes; yield; end
|