activerecord 5.0.6 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +638 -2023
- data/MIT-LICENSE +3 -1
- data/README.rdoc +8 -6
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record/aggregations.rb +249 -246
- data/lib/active_record/association_relation.rb +24 -13
- data/lib/active_record/associations/alias_tracker.rb +24 -33
- data/lib/active_record/associations/association.rb +119 -56
- data/lib/active_record/associations/association_scope.rb +94 -94
- data/lib/active_record/associations/belongs_to_association.rb +58 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +18 -25
- data/lib/active_record/associations/builder/belongs_to.rb +43 -54
- data/lib/active_record/associations/builder/collection_association.rb +7 -18
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -61
- data/lib/active_record/associations/builder/has_many.rb +4 -0
- data/lib/active_record/associations/builder/has_one.rb +37 -1
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +80 -252
- data/lib/active_record/associations/collection_proxy.rb +158 -121
- data/lib/active_record/associations/foreign_association.rb +9 -0
- data/lib/active_record/associations/has_many_association.rb +23 -29
- data/lib/active_record/associations/has_many_through_association.rb +58 -44
- data/lib/active_record/associations/has_one_association.rb +59 -54
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +38 -90
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -176
- data/lib/active_record/associations/preloader/association.rb +84 -125
- data/lib/active_record/associations/preloader/through_association.rb +82 -75
- data/lib/active_record/associations/preloader.rb +90 -102
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +26 -14
- data/lib/active_record/associations.rb +1603 -1592
- data/lib/active_record/attribute_assignment.rb +54 -60
- data/lib/active_record/attribute_decorators.rb +38 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
- data/lib/active_record/attribute_methods/dirty.rb +179 -109
- data/lib/active_record/attribute_methods/primary_key.rb +86 -91
- data/lib/active_record/attribute_methods/query.rb +4 -3
- data/lib/active_record/attribute_methods/read.rb +21 -49
- data/lib/active_record/attribute_methods/serialization.rb +30 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
- data/lib/active_record/attribute_methods/write.rb +35 -33
- data/lib/active_record/attribute_methods.rb +66 -106
- data/lib/active_record/attributes.rb +38 -24
- data/lib/active_record/autosave_association.rb +53 -32
- data/lib/active_record/base.rb +27 -24
- data/lib/active_record/callbacks.rb +63 -33
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +11 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
- data/lib/active_record/connection_adapters/column.rb +41 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +143 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
- data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -54
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -10
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +31 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +35 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
- data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -275
- data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +254 -262
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
- data/lib/active_record/connection_handling.rb +159 -40
- data/lib/active_record/core.rb +202 -162
- data/lib/active_record/counter_cache.rb +57 -28
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -86
- data/lib/active_record/enum.rb +60 -23
- data/lib/active_record/errors.rb +114 -18
- data/lib/active_record/explain.rb +4 -3
- data/lib/active_record/explain_registry.rb +3 -1
- data/lib/active_record/explain_subscriber.rb +9 -4
- data/lib/active_record/fixture_set/file.rb +13 -8
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +195 -502
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +151 -97
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +116 -25
- data/lib/active_record/internal_metadata.rb +15 -18
- data/lib/active_record/legacy_yaml_adapter.rb +4 -2
- data/lib/active_record/locking/optimistic.rb +78 -87
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +48 -29
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +143 -97
- data/lib/active_record/migration/compatibility.rb +174 -56
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +367 -300
- data/lib/active_record/model_schema.rb +145 -139
- data/lib/active_record/nested_attributes.rb +214 -201
- data/lib/active_record/no_touching.rb +10 -1
- data/lib/active_record/null_relation.rb +13 -34
- data/lib/active_record/persistence.rb +442 -72
- data/lib/active_record/query_cache.rb +15 -14
- data/lib/active_record/querying.rb +36 -23
- data/lib/active_record/railtie.rb +128 -36
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +309 -177
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +211 -249
- data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
- data/lib/active_record/relation/batches.rb +99 -52
- data/lib/active_record/relation/calculations.rb +211 -172
- data/lib/active_record/relation/delegation.rb +67 -65
- data/lib/active_record/relation/finder_methods.rb +208 -247
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +78 -61
- data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +86 -104
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +458 -329
- data/lib/active_record/relation/record_fetch_warning.rb +5 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -95
- data/lib/active_record/relation/where_clause_factory.rb +6 -11
- data/lib/active_record/relation.rb +429 -318
- data/lib/active_record/result.rb +69 -39
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +83 -99
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +71 -69
- data/lib/active_record/schema_migration.rb +15 -5
- data/lib/active_record/scoping/default.rb +93 -95
- data/lib/active_record/scoping/named.rb +45 -25
- data/lib/active_record/scoping.rb +20 -19
- data/lib/active_record/secure_token.rb +4 -2
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +63 -28
- data/lib/active_record/store.rb +121 -41
- data/lib/active_record/suppressor.rb +4 -1
- data/lib/active_record/table_metadata.rb +26 -20
- data/lib/active_record/tasks/database_tasks.rb +276 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
- data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +70 -35
- data/lib/active_record/touch_later.rb +7 -4
- data/lib/active_record/transactions.rb +133 -149
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +44 -45
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +16 -8
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +2 -1
- data/lib/active_record/type/type_map.rb +13 -15
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +23 -17
- data/lib/active_record/type_caster/connection.rb +17 -12
- data/lib/active_record/type_caster/map.rb +5 -4
- data/lib/active_record/type_caster.rb +4 -2
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +3 -1
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +29 -42
- data/lib/active_record/validations.rb +7 -4
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -22
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +58 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
- data/lib/rails/generators/active_record/migration.rb +17 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +133 -50
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -20
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute.rb +0 -213
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set/builder.rb +0 -130
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
| @@ -1,5 +1,7 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "active_support/core_ext/string/filters"
         | 
| 4 | 
            +
            require "concurrent/map"
         | 
| 3 5 |  | 
| 4 6 | 
             
            module ActiveRecord
         | 
| 5 7 | 
             
              # = Active Record Reflection
         | 
| @@ -7,37 +9,41 @@ module ActiveRecord | |
| 7 9 | 
             
                extend ActiveSupport::Concern
         | 
| 8 10 |  | 
| 9 11 | 
             
                included do
         | 
| 10 | 
            -
                  class_attribute :_reflections, instance_writer: false
         | 
| 11 | 
            -
                  class_attribute :aggregate_reflections, instance_writer: false
         | 
| 12 | 
            -
                  self._reflections = {}
         | 
| 13 | 
            -
                  self.aggregate_reflections = {}
         | 
| 12 | 
            +
                  class_attribute :_reflections, instance_writer: false, default: {}
         | 
| 13 | 
            +
                  class_attribute :aggregate_reflections, instance_writer: false, default: {}
         | 
| 14 14 | 
             
                end
         | 
| 15 15 |  | 
| 16 | 
            -
                 | 
| 17 | 
            -
                   | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
                            HasManyReflection
         | 
| 22 | 
            -
                          when :has_one
         | 
| 23 | 
            -
                            HasOneReflection
         | 
| 24 | 
            -
                          when :belongs_to
         | 
| 25 | 
            -
                            BelongsToReflection
         | 
| 26 | 
            -
                          else
         | 
| 27 | 
            -
                            raise "Unsupported Macro: #{macro}"
         | 
| 28 | 
            -
                          end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                  reflection = klass.new(name, scope, options, ar)
         | 
| 31 | 
            -
                  options[:through] ? ThroughReflection.new(reflection) : reflection
         | 
| 32 | 
            -
                end
         | 
| 16 | 
            +
                class << self
         | 
| 17 | 
            +
                  def create(macro, name, scope, options, ar)
         | 
| 18 | 
            +
                    reflection = reflection_class_for(macro).new(name, scope, options, ar)
         | 
| 19 | 
            +
                    options[:through] ? ThroughReflection.new(reflection) : reflection
         | 
| 20 | 
            +
                  end
         | 
| 33 21 |  | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 22 | 
            +
                  def add_reflection(ar, name, reflection)
         | 
| 23 | 
            +
                    ar.clear_reflections_cache
         | 
| 24 | 
            +
                    name = -name.to_s
         | 
| 25 | 
            +
                    ar._reflections = ar._reflections.except(name).merge!(name => reflection)
         | 
| 26 | 
            +
                  end
         | 
| 38 27 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 28 | 
            +
                  def add_aggregate_reflection(ar, name, reflection)
         | 
| 29 | 
            +
                    ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  private
         | 
| 33 | 
            +
                    def reflection_class_for(macro)
         | 
| 34 | 
            +
                      case macro
         | 
| 35 | 
            +
                      when :composed_of
         | 
| 36 | 
            +
                        AggregateReflection
         | 
| 37 | 
            +
                      when :has_many
         | 
| 38 | 
            +
                        HasManyReflection
         | 
| 39 | 
            +
                      when :has_one
         | 
| 40 | 
            +
                        HasOneReflection
         | 
| 41 | 
            +
                      when :belongs_to
         | 
| 42 | 
            +
                        BelongsToReflection
         | 
| 43 | 
            +
                      else
         | 
| 44 | 
            +
                        raise "Unsupported Macro: #{macro}"
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
                    end
         | 
| 41 47 | 
             
                end
         | 
| 42 48 |  | 
| 43 49 | 
             
                # \Reflection enables the ability to examine the associations and aggregations of
         | 
| @@ -135,8 +141,8 @@ module ActiveRecord | |
| 135 141 | 
             
                #         BelongsToReflection
         | 
| 136 142 | 
             
                #         HasAndBelongsToManyReflection
         | 
| 137 143 | 
             
                #     ThroughReflection
         | 
| 138 | 
            -
                # | 
| 139 | 
            -
                # | 
| 144 | 
            +
                #     PolymorphicReflection
         | 
| 145 | 
            +
                #     RuntimeReflection
         | 
| 140 146 | 
             
                class AbstractReflection # :nodoc:
         | 
| 141 147 | 
             
                  def through_reflection?
         | 
| 142 148 | 
             
                    false
         | 
| @@ -152,14 +158,6 @@ module ActiveRecord | |
| 152 158 | 
             
                    klass.new(attributes, &block)
         | 
| 153 159 | 
             
                  end
         | 
| 154 160 |  | 
| 155 | 
            -
                  def quoted_table_name
         | 
| 156 | 
            -
                    klass.quoted_table_name
         | 
| 157 | 
            -
                  end
         | 
| 158 | 
            -
             | 
| 159 | 
            -
                  def primary_key_type
         | 
| 160 | 
            -
                    klass.type_for_attribute(klass.primary_key)
         | 
| 161 | 
            -
                  end
         | 
| 162 | 
            -
             | 
| 163 161 | 
             
                  # Returns the class name for the macro.
         | 
| 164 162 | 
             
                  #
         | 
| 165 163 | 
             
                  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
         | 
| @@ -170,12 +168,52 @@ module ActiveRecord | |
| 170 168 |  | 
| 171 169 | 
             
                  JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
         | 
| 172 170 |  | 
| 173 | 
            -
                  def join_keys | 
| 174 | 
            -
                     | 
| 171 | 
            +
                  def join_keys
         | 
| 172 | 
            +
                    @join_keys ||= get_join_keys(klass)
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  # Returns a list of scopes that should be applied for this Reflection
         | 
| 176 | 
            +
                  # object when querying the database.
         | 
| 177 | 
            +
                  def scopes
         | 
| 178 | 
            +
                    scope ? [scope] : []
         | 
| 179 | 
            +
                  end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                  def join_scope(table, foreign_table, foreign_klass)
         | 
| 182 | 
            +
                    predicate_builder = predicate_builder(table)
         | 
| 183 | 
            +
                    scope_chain_items = join_scopes(table, predicate_builder)
         | 
| 184 | 
            +
                    klass_scope       = klass_join_scope(table, predicate_builder)
         | 
| 185 | 
            +
             | 
| 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 | 
            +
                    if type
         | 
| 192 | 
            +
                      klass_scope.where!(type => foreign_klass.polymorphic_name)
         | 
| 193 | 
            +
                    end
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                    if klass.finder_needs_type_condition?
         | 
| 196 | 
            +
                      klass_scope.where!(klass.send(:type_condition, table))
         | 
| 197 | 
            +
                    end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                    scope_chain_items.inject(klass_scope, &:merge!)
         | 
| 200 | 
            +
                  end
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                  def join_scopes(table, predicate_builder) # :nodoc:
         | 
| 203 | 
            +
                    if scope
         | 
| 204 | 
            +
                      [scope_for(build_scope(table, predicate_builder))]
         | 
| 205 | 
            +
                    else
         | 
| 206 | 
            +
                      []
         | 
| 207 | 
            +
                    end
         | 
| 208 | 
            +
                  end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                  def klass_join_scope(table, predicate_builder) # :nodoc:
         | 
| 211 | 
            +
                    relation = build_scope(table, predicate_builder)
         | 
| 212 | 
            +
                    klass.scope_for_association(relation)
         | 
| 175 213 | 
             
                  end
         | 
| 176 214 |  | 
| 177 215 | 
             
                  def constraints
         | 
| 178 | 
            -
                     | 
| 216 | 
            +
                    chain.flat_map(&:scopes)
         | 
| 179 217 | 
             
                  end
         | 
| 180 218 |  | 
| 181 219 | 
             
                  def counter_cache_column
         | 
| @@ -247,6 +285,40 @@ module ActiveRecord | |
| 247 285 | 
             
                  def chain
         | 
| 248 286 | 
             
                    collect_join_chain
         | 
| 249 287 | 
             
                  end
         | 
| 288 | 
            +
             | 
| 289 | 
            +
                  def get_join_keys(association_klass)
         | 
| 290 | 
            +
                    JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
         | 
| 291 | 
            +
                  end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                  def build_scope(table, predicate_builder = predicate_builder(table))
         | 
| 294 | 
            +
                    Relation.create(
         | 
| 295 | 
            +
                      klass,
         | 
| 296 | 
            +
                      table: table,
         | 
| 297 | 
            +
                      predicate_builder: predicate_builder
         | 
| 298 | 
            +
                    )
         | 
| 299 | 
            +
                  end
         | 
| 300 | 
            +
             | 
| 301 | 
            +
                  def join_primary_key(*)
         | 
| 302 | 
            +
                    foreign_key
         | 
| 303 | 
            +
                  end
         | 
| 304 | 
            +
             | 
| 305 | 
            +
                  def join_foreign_key
         | 
| 306 | 
            +
                    active_record_primary_key
         | 
| 307 | 
            +
                  end
         | 
| 308 | 
            +
             | 
| 309 | 
            +
                  protected
         | 
| 310 | 
            +
                    def actual_source_reflection # FIXME: this is a horrible name
         | 
| 311 | 
            +
                      self
         | 
| 312 | 
            +
                    end
         | 
| 313 | 
            +
             | 
| 314 | 
            +
                  private
         | 
| 315 | 
            +
                    def predicate_builder(table)
         | 
| 316 | 
            +
                      PredicateBuilder.new(TableMetadata.new(klass, table))
         | 
| 317 | 
            +
                    end
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                    def primary_key(klass)
         | 
| 320 | 
            +
                      klass.primary_key || raise(UnknownPrimaryKey.new(klass))
         | 
| 321 | 
            +
                    end
         | 
| 250 322 | 
             
                end
         | 
| 251 323 |  | 
| 252 324 | 
             
                # Base class for AggregateReflection and AssociationReflection. Objects of
         | 
| @@ -281,7 +353,6 @@ module ActiveRecord | |
| 281 353 | 
             
                  end
         | 
| 282 354 |  | 
| 283 355 | 
             
                  def autosave=(autosave)
         | 
| 284 | 
            -
                    @automatic_inverse_of = false
         | 
| 285 356 | 
             
                    @options[:autosave] = autosave
         | 
| 286 357 | 
             
                    parent_reflection = self.parent_reflection
         | 
| 287 358 | 
             
                    if parent_reflection
         | 
| @@ -293,6 +364,17 @@ module ActiveRecord | |
| 293 364 | 
             
                  #
         | 
| 294 365 | 
             
                  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
         | 
| 295 366 | 
             
                  # <tt>has_many :clients</tt> returns the Client class
         | 
| 367 | 
            +
                  #
         | 
| 368 | 
            +
                  #   class Company < ActiveRecord::Base
         | 
| 369 | 
            +
                  #     has_many :clients
         | 
| 370 | 
            +
                  #   end
         | 
| 371 | 
            +
                  #
         | 
| 372 | 
            +
                  #   Company.reflect_on_association(:clients).klass
         | 
| 373 | 
            +
                  #   # => Client
         | 
| 374 | 
            +
                  #
         | 
| 375 | 
            +
                  # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
         | 
| 376 | 
            +
                  # a new association object. Use +build_association+ or +create_association+
         | 
| 377 | 
            +
                  # instead. This allows plugins to hook into association object creation.
         | 
| 296 378 | 
             
                  def klass
         | 
| 297 379 | 
             
                    @klass ||= compute_class(class_name)
         | 
| 298 380 | 
             
                  end
         | 
| @@ -311,8 +393,8 @@ module ActiveRecord | |
| 311 393 | 
             
                      active_record == other_aggregation.active_record
         | 
| 312 394 | 
             
                  end
         | 
| 313 395 |  | 
| 314 | 
            -
                  def scope_for( | 
| 315 | 
            -
                     | 
| 396 | 
            +
                  def scope_for(relation, owner = nil)
         | 
| 397 | 
            +
                    relation.instance_exec(owner, &scope) || relation
         | 
| 316 398 | 
             
                  end
         | 
| 317 399 |  | 
| 318 400 | 
             
                  private
         | 
| @@ -321,8 +403,7 @@ module ActiveRecord | |
| 321 403 | 
             
                    end
         | 
| 322 404 | 
             
                end
         | 
| 323 405 |  | 
| 324 | 
            -
             | 
| 325 | 
            -
                # Holds all the meta-data about an aggregation as it was specified in the
         | 
| 406 | 
            +
                # Holds all the metadata about an aggregation as it was specified in the
         | 
| 326 407 | 
             
                # Active Record class.
         | 
| 327 408 | 
             
                class AggregateReflection < MacroReflection #:nodoc:
         | 
| 328 409 | 
             
                  def mapping
         | 
| @@ -331,26 +412,13 @@ module ActiveRecord | |
| 331 412 | 
             
                  end
         | 
| 332 413 | 
             
                end
         | 
| 333 414 |  | 
| 334 | 
            -
                # Holds all the  | 
| 415 | 
            +
                # Holds all the metadata about an association as it was specified in the
         | 
| 335 416 | 
             
                # Active Record class.
         | 
| 336 417 | 
             
                class AssociationReflection < MacroReflection #:nodoc:
         | 
| 337 | 
            -
                  # Returns the target association's class.
         | 
| 338 | 
            -
                  #
         | 
| 339 | 
            -
                  #   class Author < ActiveRecord::Base
         | 
| 340 | 
            -
                  #     has_many :books
         | 
| 341 | 
            -
                  #   end
         | 
| 342 | 
            -
                  #
         | 
| 343 | 
            -
                  #   Author.reflect_on_association(:books).klass
         | 
| 344 | 
            -
                  #   # => Book
         | 
| 345 | 
            -
                  #
         | 
| 346 | 
            -
                  # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
         | 
| 347 | 
            -
                  # a new association object. Use +build_association+ or +create_association+
         | 
| 348 | 
            -
                  # instead. This allows plugins to hook into association object creation.
         | 
| 349 | 
            -
                  def klass
         | 
| 350 | 
            -
                    @klass ||= compute_class(class_name)
         | 
| 351 | 
            -
                  end
         | 
| 352 | 
            -
             | 
| 353 418 | 
             
                  def compute_class(name)
         | 
| 419 | 
            +
                    if polymorphic?
         | 
| 420 | 
            +
                      raise ArgumentError, "Polymorphic associations do not support computing the class."
         | 
| 421 | 
            +
                    end
         | 
| 354 422 | 
             
                    active_record.send(:compute_type, name)
         | 
| 355 423 | 
             
                  end
         | 
| 356 424 |  | 
| @@ -359,22 +427,22 @@ module ActiveRecord | |
| 359 427 |  | 
| 360 428 | 
             
                  def initialize(name, scope, options, active_record)
         | 
| 361 429 | 
             
                    super
         | 
| 362 | 
            -
                    @automatic_inverse_of = nil
         | 
| 363 430 | 
             
                    @type         = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
         | 
| 364 | 
            -
                    @foreign_type = options[:foreign_type] || "#{name}_type"
         | 
| 431 | 
            +
                    @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
         | 
| 365 432 | 
             
                    @constructable = calculate_constructable(macro, options)
         | 
| 366 | 
            -
                    @association_scope_cache =  | 
| 367 | 
            -
             | 
| 433 | 
            +
                    @association_scope_cache = Concurrent::Map.new
         | 
| 434 | 
            +
             | 
| 435 | 
            +
                    if options[:class_name] && options[:class_name].class == Class
         | 
| 436 | 
            +
                      raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
         | 
| 437 | 
            +
                    end
         | 
| 368 438 | 
             
                  end
         | 
| 369 439 |  | 
| 370 | 
            -
                  def association_scope_cache(conn, owner)
         | 
| 440 | 
            +
                  def association_scope_cache(conn, owner, &block)
         | 
| 371 441 | 
             
                    key = conn.prepared_statements
         | 
| 372 442 | 
             
                    if polymorphic?
         | 
| 373 443 | 
             
                      key = [key, owner._read_attribute(@foreign_type)]
         | 
| 374 444 | 
             
                    end
         | 
| 375 | 
            -
                    @association_scope_cache | 
| 376 | 
            -
                      @association_scope_cache[key] ||= yield
         | 
| 377 | 
            -
                    }
         | 
| 445 | 
            +
                    @association_scope_cache.compute_if_absent(key) { StatementCache.create(conn, &block) }
         | 
| 378 446 | 
             
                  end
         | 
| 379 447 |  | 
| 380 448 | 
             
                  def constructable? # :nodoc:
         | 
| @@ -398,10 +466,6 @@ module ActiveRecord | |
| 398 466 | 
             
                    options[:primary_key] || primary_key(klass || self.klass)
         | 
| 399 467 | 
             
                  end
         | 
| 400 468 |  | 
| 401 | 
            -
                  def association_primary_key_type
         | 
| 402 | 
            -
                    klass.type_for_attribute(association_primary_key.to_s)
         | 
| 403 | 
            -
                  end
         | 
| 404 | 
            -
             | 
| 405 469 | 
             
                  def active_record_primary_key
         | 
| 406 470 | 
             
                    @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
         | 
| 407 471 | 
             
                  end
         | 
| @@ -413,7 +477,7 @@ module ActiveRecord | |
| 413 477 | 
             
                  def check_preloadable!
         | 
| 414 478 | 
             
                    return unless scope
         | 
| 415 479 |  | 
| 416 | 
            -
                     | 
| 480 | 
            +
                    unless scope.arity == 0
         | 
| 417 481 | 
             
                      raise ArgumentError, <<-MSG.squish
         | 
| 418 482 | 
             
                        The association scope '#{name}' is instance dependent (the scope
         | 
| 419 483 | 
             
                        block takes an argument). Preloading instance dependent scopes is
         | 
| @@ -424,7 +488,7 @@ module ActiveRecord | |
| 424 488 | 
             
                  alias :check_eager_loadable! :check_preloadable!
         | 
| 425 489 |  | 
| 426 490 | 
             
                  def join_id_for(owner) # :nodoc:
         | 
| 427 | 
            -
                    owner[ | 
| 491 | 
            +
                    owner[join_foreign_key]
         | 
| 428 492 | 
             
                  end
         | 
| 429 493 |  | 
| 430 494 | 
             
                  def through_reflection
         | 
| @@ -451,12 +515,6 @@ module ActiveRecord | |
| 451 515 | 
             
                    false
         | 
| 452 516 | 
             
                  end
         | 
| 453 517 |  | 
| 454 | 
            -
                  # An array of arrays of scopes. Each item in the outside array corresponds to a reflection
         | 
| 455 | 
            -
                  # in the #chain.
         | 
| 456 | 
            -
                  def scope_chain
         | 
| 457 | 
            -
                    scope ? [[scope]] : [[]]
         | 
| 458 | 
            -
                  end
         | 
| 459 | 
            -
             | 
| 460 518 | 
             
                  def has_scope?
         | 
| 461 519 | 
             
                    scope
         | 
| 462 520 | 
             
                  end
         | 
| @@ -513,7 +571,7 @@ module ActiveRecord | |
| 513 571 | 
             
                  end
         | 
| 514 572 |  | 
| 515 573 | 
             
                  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
         | 
| 516 | 
            -
                  INVALID_AUTOMATIC_INVERSE_OPTIONS = [: | 
| 574 | 
            +
                  INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
         | 
| 517 575 |  | 
| 518 576 | 
             
                  def add_as_source(seed)
         | 
| 519 577 | 
             
                    seed
         | 
| @@ -531,12 +589,6 @@ module ActiveRecord | |
| 531 589 | 
             
                    Array(options[:extend])
         | 
| 532 590 | 
             
                  end
         | 
| 533 591 |  | 
| 534 | 
            -
                  protected
         | 
| 535 | 
            -
             | 
| 536 | 
            -
                    def actual_source_reflection # FIXME: this is a horrible name
         | 
| 537 | 
            -
                      self
         | 
| 538 | 
            -
                    end
         | 
| 539 | 
            -
             | 
| 540 592 | 
             
                  private
         | 
| 541 593 |  | 
| 542 594 | 
             
                    def calculate_constructable(macro, options)
         | 
| @@ -545,18 +597,16 @@ module ActiveRecord | |
| 545 597 |  | 
| 546 598 | 
             
                    # Attempts to find the inverse association name automatically.
         | 
| 547 599 | 
             
                    # If it cannot find a suitable inverse association name, it returns
         | 
| 548 | 
            -
                    # nil | 
| 600 | 
            +
                    # +nil+.
         | 
| 549 601 | 
             
                    def inverse_name
         | 
| 550 | 
            -
                       | 
| 551 | 
            -
                         | 
| 552 | 
            -
                          nil
         | 
| 553 | 
            -
                        else
         | 
| 554 | 
            -
                          @automatic_inverse_of ||= automatic_inverse_of
         | 
| 555 | 
            -
                        end
         | 
| 602 | 
            +
                      unless defined?(@inverse_name)
         | 
| 603 | 
            +
                        @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
         | 
| 556 604 | 
             
                      end
         | 
| 605 | 
            +
             | 
| 606 | 
            +
                      @inverse_name
         | 
| 557 607 | 
             
                    end
         | 
| 558 608 |  | 
| 559 | 
            -
                    # returns either  | 
| 609 | 
            +
                    # returns either +nil+ or the inverse association name that it finds.
         | 
| 560 610 | 
             
                    def automatic_inverse_of
         | 
| 561 611 | 
             
                      if can_find_inverse_of_automatically?(self)
         | 
| 562 612 | 
             
                        inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
         | 
| @@ -573,20 +623,15 @@ module ActiveRecord | |
| 573 623 | 
             
                          return inverse_name
         | 
| 574 624 | 
             
                        end
         | 
| 575 625 | 
             
                      end
         | 
| 576 | 
            -
             | 
| 577 | 
            -
                      false
         | 
| 578 626 | 
             
                    end
         | 
| 579 627 |  | 
| 580 628 | 
             
                    # Checks if the inverse reflection that is returned from the
         | 
| 581 629 | 
             
                    # +automatic_inverse_of+ method is a valid reflection. We must
         | 
| 582 630 | 
             
                    # make sure that the reflection's active_record name matches up
         | 
| 583 631 | 
             
                    # with the current reflection's klass name.
         | 
| 584 | 
            -
                    #
         | 
| 585 | 
            -
                    # Note: klass will always be valid because when there's a NameError
         | 
| 586 | 
            -
                    # from calling +klass+, +reflection+ will already be set to false.
         | 
| 587 632 | 
             
                    def valid_inverse_reflection?(reflection)
         | 
| 588 633 | 
             
                      reflection &&
         | 
| 589 | 
            -
                        klass | 
| 634 | 
            +
                        klass <= reflection.active_record &&
         | 
| 590 635 | 
             
                        can_find_inverse_of_automatically?(reflection)
         | 
| 591 636 | 
             
                    end
         | 
| 592 637 |  | 
| @@ -594,9 +639,8 @@ module ActiveRecord | |
| 594 639 | 
             
                    # us from being able to guess the inverse automatically. First, the
         | 
| 595 640 | 
             
                    # <tt>inverse_of</tt> option cannot be set to false. Second, we must
         | 
| 596 641 | 
             
                    # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
         | 
| 597 | 
            -
                    # Third, we must not have options such as <tt>: | 
| 598 | 
            -
                    #  | 
| 599 | 
            -
                    # inverse association.
         | 
| 642 | 
            +
                    # Third, we must not have options such as <tt>:foreign_key</tt>
         | 
| 643 | 
            +
                    # which prevent us from correctly guessing the inverse association.
         | 
| 600 644 | 
             
                    #
         | 
| 601 645 | 
             
                    # Anything with a scope can additionally ruin our attempt at finding an
         | 
| 602 646 | 
             
                    # inverse, so we exclude reflections with scopes.
         | 
| @@ -626,10 +670,6 @@ module ActiveRecord | |
| 626 670 | 
             
                    def derive_join_table
         | 
| 627 671 | 
             
                      ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
         | 
| 628 672 | 
             
                    end
         | 
| 629 | 
            -
             | 
| 630 | 
            -
                    def primary_key(klass)
         | 
| 631 | 
            -
                      klass.primary_key || raise(UnknownPrimaryKey.new(klass))
         | 
| 632 | 
            -
                    end
         | 
| 633 673 | 
             
                end
         | 
| 634 674 |  | 
| 635 675 | 
             
                class HasManyReflection < AssociationReflection # :nodoc:
         | 
| @@ -683,16 +723,18 @@ module ActiveRecord | |
| 683 723 | 
             
                    end
         | 
| 684 724 | 
             
                  end
         | 
| 685 725 |  | 
| 686 | 
            -
                  def  | 
| 687 | 
            -
                     | 
| 688 | 
            -
                    JoinKeys.new(key, foreign_key)
         | 
| 726 | 
            +
                  def join_primary_key(klass = nil)
         | 
| 727 | 
            +
                    polymorphic? ? association_primary_key(klass) : association_primary_key
         | 
| 689 728 | 
             
                  end
         | 
| 690 729 |  | 
| 691 | 
            -
                  def  | 
| 692 | 
            -
                     | 
| 730 | 
            +
                  def join_foreign_key
         | 
| 731 | 
            +
                    foreign_key
         | 
| 693 732 | 
             
                  end
         | 
| 694 733 |  | 
| 695 734 | 
             
                  private
         | 
| 735 | 
            +
                    def can_find_inverse_of_automatically?(_)
         | 
| 736 | 
            +
                      !polymorphic? && super
         | 
| 737 | 
            +
                    end
         | 
| 696 738 |  | 
| 697 739 | 
             
                    def calculate_constructable(macro, options)
         | 
| 698 740 | 
             
                      !polymorphic?
         | 
| @@ -700,10 +742,6 @@ module ActiveRecord | |
| 700 742 | 
             
                end
         | 
| 701 743 |  | 
| 702 744 | 
             
                class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
         | 
| 703 | 
            -
                  def initialize(name, scope, options, active_record)
         | 
| 704 | 
            -
                    super
         | 
| 705 | 
            -
                  end
         | 
| 706 | 
            -
             | 
| 707 745 | 
             
                  def macro; :has_and_belongs_to_many; end
         | 
| 708 746 |  | 
| 709 747 | 
             
                  def collection?
         | 
| @@ -711,16 +749,15 @@ module ActiveRecord | |
| 711 749 | 
             
                  end
         | 
| 712 750 | 
             
                end
         | 
| 713 751 |  | 
| 714 | 
            -
                # Holds all the  | 
| 752 | 
            +
                # Holds all the metadata about a :through association as it was specified
         | 
| 715 753 | 
             
                # in the Active Record class.
         | 
| 716 754 | 
             
                class ThroughReflection < AbstractReflection #:nodoc:
         | 
| 717 | 
            -
                   | 
| 718 | 
            -
             | 
| 719 | 
            -
                           :active_record_primary_key, :type, :to => :source_reflection
         | 
| 755 | 
            +
                  delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
         | 
| 756 | 
            +
                           :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
         | 
| 720 757 |  | 
| 721 758 | 
             
                  def initialize(delegate_reflection)
         | 
| 722 759 | 
             
                    @delegate_reflection = delegate_reflection
         | 
| 723 | 
            -
                    @klass | 
| 760 | 
            +
                    @klass = delegate_reflection.options[:anonymous_class]
         | 
| 724 761 | 
             
                    @source_reflection_name = delegate_reflection.options[:source]
         | 
| 725 762 | 
             
                  end
         | 
| 726 763 |  | 
| @@ -798,45 +835,12 @@ module ActiveRecord | |
| 798 835 | 
             
                    through_reflection.clear_association_scope_cache
         | 
| 799 836 | 
             
                  end
         | 
| 800 837 |  | 
| 801 | 
            -
                   | 
| 802 | 
            -
             | 
| 803 | 
            -
                   | 
| 804 | 
            -
                  #     has_many :articles
         | 
| 805 | 
            -
                  #     has_many :comment_tags, through: :articles
         | 
| 806 | 
            -
                  #   end
         | 
| 807 | 
            -
                  #
         | 
| 808 | 
            -
                  #   class Article
         | 
| 809 | 
            -
                  #     has_many :comments
         | 
| 810 | 
            -
                  #     has_many :comment_tags, through: :comments, source: :tags
         | 
| 811 | 
            -
                  #   end
         | 
| 812 | 
            -
                  #
         | 
| 813 | 
            -
                  #   class Comment
         | 
| 814 | 
            -
                  #     has_many :tags
         | 
| 815 | 
            -
                  #   end
         | 
| 816 | 
            -
                  #
         | 
| 817 | 
            -
                  # There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags,
         | 
| 818 | 
            -
                  # but only Comment.tags will be represented in the #chain. So this method creates an array
         | 
| 819 | 
            -
                  # of scopes corresponding to the chain.
         | 
| 820 | 
            -
                  def scope_chain
         | 
| 821 | 
            -
                    @scope_chain ||= begin
         | 
| 822 | 
            -
                      scope_chain = source_reflection.scope_chain.map(&:dup)
         | 
| 823 | 
            -
             | 
| 824 | 
            -
                      # Add to it the scope from this reflection (if any)
         | 
| 825 | 
            -
                      scope_chain.first << scope if scope
         | 
| 826 | 
            -
             | 
| 827 | 
            -
                      through_scope_chain = through_reflection.scope_chain.map(&:dup)
         | 
| 828 | 
            -
             | 
| 829 | 
            -
                      if options[:source_type]
         | 
| 830 | 
            -
                        type = foreign_type
         | 
| 831 | 
            -
                        source_type = options[:source_type]
         | 
| 832 | 
            -
                        through_scope_chain.first << lambda { |object|
         | 
| 833 | 
            -
                          where(type => source_type)
         | 
| 834 | 
            -
                        }
         | 
| 835 | 
            -
                      end
         | 
| 838 | 
            +
                  def scopes
         | 
| 839 | 
            +
                    source_reflection.scopes + super
         | 
| 840 | 
            +
                  end
         | 
| 836 841 |  | 
| 837 | 
            -
             | 
| 838 | 
            -
             | 
| 839 | 
            -
                    end
         | 
| 842 | 
            +
                  def join_scopes(table, predicate_builder) # :nodoc:
         | 
| 843 | 
            +
                    source_reflection.join_scopes(table, predicate_builder) + super
         | 
| 840 844 | 
             
                  end
         | 
| 841 845 |  | 
| 842 846 | 
             
                  def has_scope?
         | 
| @@ -845,10 +849,6 @@ module ActiveRecord | |
| 845 849 | 
             
                      through_reflection.has_scope?
         | 
| 846 850 | 
             
                  end
         | 
| 847 851 |  | 
| 848 | 
            -
                  def join_keys(association_klass)
         | 
| 849 | 
            -
                    source_reflection.join_keys(association_klass)
         | 
| 850 | 
            -
                  end
         | 
| 851 | 
            -
             | 
| 852 852 | 
             
                  # A through association is nested if there would be more than one join table
         | 
| 853 853 | 
             
                  def nested?
         | 
| 854 854 | 
             
                    source_reflection.through_reflection? || through_reflection.through_reflection?
         | 
| @@ -863,10 +863,6 @@ module ActiveRecord | |
| 863 863 | 
             
                    actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
         | 
| 864 864 | 
             
                  end
         | 
| 865 865 |  | 
| 866 | 
            -
                  def association_primary_key_type
         | 
| 867 | 
            -
                    klass.type_for_attribute(association_primary_key.to_s)
         | 
| 868 | 
            -
                  end
         | 
| 869 | 
            -
             | 
| 870 866 | 
             
                  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
         | 
| 871 867 | 
             
                  #
         | 
| 872 868 | 
             
                  #   class Post < ActiveRecord::Base
         | 
| @@ -891,15 +887,13 @@ module ActiveRecord | |
| 891 887 | 
             
                    }
         | 
| 892 888 |  | 
| 893 889 | 
             
                    if names.length > 1
         | 
| 894 | 
            -
                       | 
| 895 | 
            -
             | 
| 896 | 
            -
             | 
| 897 | 
            -
                         | 
| 898 | 
            -
                         | 
| 899 | 
            -
                         | 
| 900 | 
            -
             | 
| 901 | 
            -
                        "    #{macro} :#{name}, #{example_options}\n" \
         | 
| 902 | 
            -
                        "  end"
         | 
| 890 | 
            +
                      raise AmbiguousSourceReflectionForThroughAssociation.new(
         | 
| 891 | 
            +
                        active_record.name,
         | 
| 892 | 
            +
                        macro,
         | 
| 893 | 
            +
                        name,
         | 
| 894 | 
            +
                        options,
         | 
| 895 | 
            +
                        source_reflection_names
         | 
| 896 | 
            +
                      )
         | 
| 903 897 | 
             
                    end
         | 
| 904 898 |  | 
| 905 899 | 
             
                    @source_reflection_name = names.first
         | 
| @@ -913,10 +907,6 @@ module ActiveRecord | |
| 913 907 | 
             
                    through_reflection.options
         | 
| 914 908 | 
             
                  end
         | 
| 915 909 |  | 
| 916 | 
            -
                  def join_id_for(owner) # :nodoc:
         | 
| 917 | 
            -
                    source_reflection.join_id_for(owner)
         | 
| 918 | 
            -
                  end
         | 
| 919 | 
            -
             | 
| 920 910 | 
             
                  def check_validity!
         | 
| 921 911 | 
             
                    if through_reflection.nil?
         | 
| 922 912 | 
             
                      raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
         | 
| @@ -946,6 +936,14 @@ module ActiveRecord | |
| 946 936 | 
             
                      raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
         | 
| 947 937 | 
             
                    end
         | 
| 948 938 |  | 
| 939 | 
            +
                    if parent_reflection.nil?
         | 
| 940 | 
            +
                      reflections = active_record.reflections.keys.map(&:to_sym)
         | 
| 941 | 
            +
             | 
| 942 | 
            +
                      if reflections.index(through_reflection.name) > reflections.index(name)
         | 
| 943 | 
            +
                        raise HasManyThroughOrderError.new(active_record.name, self, through_reflection)
         | 
| 944 | 
            +
                      end
         | 
| 945 | 
            +
                    end
         | 
| 946 | 
            +
             | 
| 949 947 | 
             
                    check_validity_of_inverse!
         | 
| 950 948 | 
             
                  end
         | 
| 951 949 |  | 
| @@ -967,28 +965,25 @@ module ActiveRecord | |
| 967 965 | 
             
                    collect_join_reflections(seed + [self])
         | 
| 968 966 | 
             
                  end
         | 
| 969 967 |  | 
| 970 | 
            -
                  def collect_join_reflections(seed)
         | 
| 971 | 
            -
                    a = source_reflection.add_as_source seed
         | 
| 972 | 
            -
                    if options[:source_type]
         | 
| 973 | 
            -
                      through_reflection.add_as_polymorphic_through self, a
         | 
| 974 | 
            -
                    else
         | 
| 975 | 
            -
                      through_reflection.add_as_through a
         | 
| 976 | 
            -
                    end
         | 
| 977 | 
            -
                  end
         | 
| 978 | 
            -
             | 
| 979 968 | 
             
                  protected
         | 
| 980 | 
            -
             | 
| 981 969 | 
             
                    def actual_source_reflection # FIXME: this is a horrible name
         | 
| 982 | 
            -
                      source_reflection. | 
| 970 | 
            +
                      source_reflection.actual_source_reflection
         | 
| 983 971 | 
             
                    end
         | 
| 984 972 |  | 
| 985 | 
            -
             | 
| 986 | 
            -
             | 
| 973 | 
            +
                  private
         | 
| 974 | 
            +
                    attr_reader :delegate_reflection
         | 
| 975 | 
            +
             | 
| 976 | 
            +
                    def collect_join_reflections(seed)
         | 
| 977 | 
            +
                      a = source_reflection.add_as_source seed
         | 
| 978 | 
            +
                      if options[:source_type]
         | 
| 979 | 
            +
                        through_reflection.add_as_polymorphic_through self, a
         | 
| 980 | 
            +
                      else
         | 
| 981 | 
            +
                        through_reflection.add_as_through a
         | 
| 982 | 
            +
                      end
         | 
| 987 983 | 
             
                    end
         | 
| 988 984 |  | 
| 989 985 | 
             
                    def inverse_name; delegate_reflection.send(:inverse_name); end
         | 
| 990 986 |  | 
| 991 | 
            -
                  private
         | 
| 992 987 | 
             
                    def derive_class_name
         | 
| 993 988 | 
             
                      # get the class_name of the belongs_to association of the through reflection
         | 
| 994 989 | 
             
                      options[:source_type] || source_reflection.class_name
         | 
| @@ -998,52 +993,35 @@ module ActiveRecord | |
| 998 993 | 
             
                      public_instance_methods
         | 
| 999 994 |  | 
| 1000 995 | 
             
                    delegate(*delegate_methods, to: :delegate_reflection)
         | 
| 1001 | 
            -
             | 
| 1002 996 | 
             
                end
         | 
| 1003 997 |  | 
| 1004 | 
            -
                class PolymorphicReflection <  | 
| 998 | 
            +
                class PolymorphicReflection < AbstractReflection # :nodoc:
         | 
| 999 | 
            +
                  delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
         | 
| 1000 | 
            +
             | 
| 1005 1001 | 
             
                  def initialize(reflection, previous_reflection)
         | 
| 1006 1002 | 
             
                    @reflection = reflection
         | 
| 1007 1003 | 
             
                    @previous_reflection = previous_reflection
         | 
| 1008 1004 | 
             
                  end
         | 
| 1009 1005 |  | 
| 1010 | 
            -
                  def  | 
| 1011 | 
            -
                    @ | 
| 1012 | 
            -
             | 
| 1013 | 
            -
             | 
| 1014 | 
            -
                  def scope
         | 
| 1015 | 
            -
                    @reflection.scope
         | 
| 1016 | 
            -
                  end
         | 
| 1017 | 
            -
             | 
| 1018 | 
            -
                  def table_name
         | 
| 1019 | 
            -
                    @reflection.table_name
         | 
| 1020 | 
            -
                  end
         | 
| 1021 | 
            -
             | 
| 1022 | 
            -
                  def plural_name
         | 
| 1023 | 
            -
                    @reflection.plural_name
         | 
| 1024 | 
            -
                  end
         | 
| 1025 | 
            -
             | 
| 1026 | 
            -
                  def join_keys(association_klass)
         | 
| 1027 | 
            -
                    @reflection.join_keys(association_klass)
         | 
| 1028 | 
            -
                  end
         | 
| 1029 | 
            -
             | 
| 1030 | 
            -
                  def type
         | 
| 1031 | 
            -
                    @reflection.type
         | 
| 1006 | 
            +
                  def join_scopes(table, predicate_builder) # :nodoc:
         | 
| 1007 | 
            +
                    scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
         | 
| 1008 | 
            +
                    scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
         | 
| 1032 1009 | 
             
                  end
         | 
| 1033 1010 |  | 
| 1034 1011 | 
             
                  def constraints
         | 
| 1035 | 
            -
                    @reflection.constraints + [ | 
| 1012 | 
            +
                    @reflection.constraints + [source_type_scope]
         | 
| 1036 1013 | 
             
                  end
         | 
| 1037 1014 |  | 
| 1038 | 
            -
                   | 
| 1039 | 
            -
                     | 
| 1040 | 
            -
             | 
| 1041 | 
            -
             | 
| 1042 | 
            -
             | 
| 1015 | 
            +
                  private
         | 
| 1016 | 
            +
                    def source_type_scope
         | 
| 1017 | 
            +
                      type = @previous_reflection.foreign_type
         | 
| 1018 | 
            +
                      source_type = @previous_reflection.options[:source_type]
         | 
| 1019 | 
            +
                      lambda { |object| where(type => source_type) }
         | 
| 1020 | 
            +
                    end
         | 
| 1043 1021 | 
             
                end
         | 
| 1044 1022 |  | 
| 1045 | 
            -
                class RuntimeReflection <  | 
| 1046 | 
            -
                   | 
| 1023 | 
            +
                class RuntimeReflection < AbstractReflection # :nodoc:
         | 
| 1024 | 
            +
                  delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
         | 
| 1047 1025 |  | 
| 1048 1026 | 
             
                  def initialize(reflection, association)
         | 
| 1049 1027 | 
             
                    @reflection = reflection
         | 
| @@ -1054,24 +1032,8 @@ module ActiveRecord | |
| 1054 1032 | 
             
                    @association.klass
         | 
| 1055 1033 | 
             
                  end
         | 
| 1056 1034 |  | 
| 1057 | 
            -
                  def  | 
| 1058 | 
            -
                    klass. | 
| 1059 | 
            -
                  end
         | 
| 1060 | 
            -
             | 
| 1061 | 
            -
                  def constraints
         | 
| 1062 | 
            -
                    @reflection.constraints
         | 
| 1063 | 
            -
                  end
         | 
| 1064 | 
            -
             | 
| 1065 | 
            -
                  def source_type_info
         | 
| 1066 | 
            -
                    @reflection.source_type_info
         | 
| 1067 | 
            -
                  end
         | 
| 1068 | 
            -
             | 
| 1069 | 
            -
                  def alias_candidate(name)
         | 
| 1070 | 
            -
                    "#{plural_name}_#{name}_join"
         | 
| 1071 | 
            -
                  end
         | 
| 1072 | 
            -
             | 
| 1073 | 
            -
                  def alias_name
         | 
| 1074 | 
            -
                    Arel::Table.new(table_name)
         | 
| 1035 | 
            +
                  def aliased_table
         | 
| 1036 | 
            +
                    @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
         | 
| 1075 1037 | 
             
                  end
         | 
| 1076 1038 |  | 
| 1077 1039 | 
             
                  def all_includes; yield; end
         |