activerecord 5.2.8 → 7.0.2
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 +4 -4
 - data/CHANGELOG.md +1393 -587
 - data/MIT-LICENSE +3 -1
 - data/README.rdoc +7 -5
 - data/examples/performance.rb +1 -1
 - data/lib/active_record/aggregations.rb +10 -9
 - data/lib/active_record/association_relation.rb +22 -12
 - data/lib/active_record/associations/alias_tracker.rb +19 -16
 - data/lib/active_record/associations/association.rb +122 -47
 - data/lib/active_record/associations/association_scope.rb +24 -24
 - data/lib/active_record/associations/belongs_to_association.rb +67 -49
 - data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -7
 - data/lib/active_record/associations/builder/association.rb +52 -23
 - data/lib/active_record/associations/builder/belongs_to.rb +44 -61
 - data/lib/active_record/associations/builder/collection_association.rb +17 -19
 - data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
 - data/lib/active_record/associations/builder/has_many.rb +10 -3
 - data/lib/active_record/associations/builder/has_one.rb +35 -3
 - data/lib/active_record/associations/builder/singular_association.rb +5 -3
 - data/lib/active_record/associations/collection_association.rb +59 -50
 - data/lib/active_record/associations/collection_proxy.rb +32 -23
 - data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
 - data/lib/active_record/associations/foreign_association.rb +20 -0
 - data/lib/active_record/associations/has_many_association.rb +27 -14
 - data/lib/active_record/associations/has_many_through_association.rb +26 -19
 - data/lib/active_record/associations/has_one_association.rb +52 -37
 - data/lib/active_record/associations/has_one_through_association.rb +6 -6
 - data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
 - data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
 - data/lib/active_record/associations/join_dependency.rb +97 -62
 - data/lib/active_record/associations/preloader/association.rb +220 -60
 - data/lib/active_record/associations/preloader/batch.rb +48 -0
 - data/lib/active_record/associations/preloader/branch.rb +147 -0
 - data/lib/active_record/associations/preloader/through_association.rb +85 -40
 - data/lib/active_record/associations/preloader.rb +44 -105
 - data/lib/active_record/associations/singular_association.rb +9 -17
 - data/lib/active_record/associations/through_association.rb +4 -4
 - data/lib/active_record/associations.rb +207 -66
 - data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
 - data/lib/active_record/attribute_assignment.rb +17 -19
 - data/lib/active_record/attribute_methods/before_type_cast.rb +19 -8
 - data/lib/active_record/attribute_methods/dirty.rb +141 -47
 - data/lib/active_record/attribute_methods/primary_key.rb +22 -27
 - data/lib/active_record/attribute_methods/query.rb +6 -10
 - data/lib/active_record/attribute_methods/read.rb +15 -55
 - data/lib/active_record/attribute_methods/serialization.rb +77 -18
 - data/lib/active_record/attribute_methods/time_zone_conversion.rb +16 -18
 - data/lib/active_record/attribute_methods/write.rb +18 -37
 - data/lib/active_record/attribute_methods.rb +90 -153
 - data/lib/active_record/attributes.rb +38 -12
 - data/lib/active_record/autosave_association.rb +50 -50
 - data/lib/active_record/base.rb +23 -18
 - data/lib/active_record/callbacks.rb +159 -44
 - data/lib/active_record/coders/yaml_column.rb +12 -3
 - data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
 - data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
 - data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
 - data/lib/active_record/connection_adapters/abstract/connection_pool.rb +92 -464
 - data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -51
 - data/lib/active_record/connection_adapters/abstract/database_statements.rb +209 -164
 - data/lib/active_record/connection_adapters/abstract/query_cache.rb +38 -22
 - data/lib/active_record/connection_adapters/abstract/quoting.rb +103 -82
 - data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
 - data/lib/active_record/connection_adapters/abstract/schema_creation.rb +140 -110
 - data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -94
 - data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +16 -5
 - data/lib/active_record/connection_adapters/abstract/schema_statements.rb +456 -159
 - data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
 - data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -162
 - data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +311 -327
 - data/lib/active_record/connection_adapters/column.rb +33 -11
 - data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
 - data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
 - data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
 - data/lib/active_record/connection_adapters/mysql/database_statements.rb +113 -45
 - data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
 - data/lib/active_record/connection_adapters/mysql/quoting.rb +71 -5
 - data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
 - data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
 - data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +25 -8
 - data/lib/active_record/connection_adapters/mysql/schema_statements.rb +143 -19
 - data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
 - data/lib/active_record/connection_adapters/mysql2_adapter.rb +63 -22
 - data/lib/active_record/connection_adapters/pool_config.rb +73 -0
 - data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
 - data/lib/active_record/connection_adapters/postgresql/column.rb +53 -28
 - data/lib/active_record/connection_adapters/postgresql/database_statements.rb +56 -63
 - data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
 - data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
 - data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -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 +54 -16
 - data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
 - data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
 - data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
 - data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
 - 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 +26 -12
 - data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
 - data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
 - data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -52
 - data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -2
 - data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +39 -4
 - data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +128 -91
 - data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -1
 - data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +149 -113
 - data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
 - data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
 - data/lib/active_record/connection_adapters/postgresql_adapter.rb +386 -182
 - data/lib/active_record/connection_adapters/schema_cache.rb +161 -22
 - data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
 - data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +152 -0
 - data/lib/active_record/connection_adapters/sqlite3/quoting.rb +65 -18
 - data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
 - data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +92 -26
 - data/lib/active_record/connection_adapters/sqlite3_adapter.rb +251 -204
 - data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
 - data/lib/active_record/connection_adapters.rb +53 -0
 - data/lib/active_record/connection_handling.rb +292 -38
 - data/lib/active_record/core.rb +385 -158
 - data/lib/active_record/counter_cache.rb +8 -30
 - data/lib/active_record/database_configurations/connection_url_resolver.rb +100 -0
 - data/lib/active_record/database_configurations/database_config.rb +83 -0
 - data/lib/active_record/database_configurations/hash_config.rb +154 -0
 - data/lib/active_record/database_configurations/url_config.rb +53 -0
 - data/lib/active_record/database_configurations.rb +256 -0
 - data/lib/active_record/delegated_type.rb +250 -0
 - data/lib/active_record/destroy_association_async_job.rb +36 -0
 - data/lib/active_record/disable_joins_association_relation.rb +39 -0
 - data/lib/active_record/dynamic_matchers.rb +4 -5
 - data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
 - data/lib/active_record/encryption/cipher.rb +53 -0
 - data/lib/active_record/encryption/config.rb +44 -0
 - data/lib/active_record/encryption/configurable.rb +61 -0
 - data/lib/active_record/encryption/context.rb +35 -0
 - data/lib/active_record/encryption/contexts.rb +72 -0
 - data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
 - data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
 - data/lib/active_record/encryption/encryptable_record.rb +208 -0
 - data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -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 +155 -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 +160 -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 +42 -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_serializer.rb +90 -0
 - data/lib/active_record/encryption/null_encryptor.rb +21 -0
 - data/lib/active_record/encryption/properties.rb +76 -0
 - data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
 - data/lib/active_record/encryption/scheme.rb +99 -0
 - data/lib/active_record/encryption.rb +55 -0
 - data/lib/active_record/enum.rb +130 -51
 - data/lib/active_record/errors.rb +129 -23
 - data/lib/active_record/explain.rb +10 -6
 - data/lib/active_record/explain_registry.rb +11 -6
 - data/lib/active_record/explain_subscriber.rb +1 -1
 - data/lib/active_record/fixture_set/file.rb +22 -15
 - data/lib/active_record/fixture_set/model_metadata.rb +32 -0
 - data/lib/active_record/fixture_set/render_context.rb +17 -0
 - data/lib/active_record/fixture_set/table_row.rb +187 -0
 - data/lib/active_record/fixture_set/table_rows.rb +46 -0
 - data/lib/active_record/fixtures.rb +206 -490
 - data/lib/active_record/future_result.rb +139 -0
 - data/lib/active_record/gem_version.rb +3 -3
 - data/lib/active_record/inheritance.rb +104 -37
 - data/lib/active_record/insert_all.rb +278 -0
 - data/lib/active_record/integration.rb +69 -18
 - data/lib/active_record/internal_metadata.rb +24 -9
 - data/lib/active_record/legacy_yaml_adapter.rb +3 -36
 - data/lib/active_record/locking/optimistic.rb +41 -26
 - data/lib/active_record/locking/pessimistic.rb +18 -8
 - data/lib/active_record/log_subscriber.rb +46 -35
 - data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
 - data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
 - data/lib/active_record/middleware/database_selector.rb +82 -0
 - data/lib/active_record/middleware/shard_selector.rb +60 -0
 - data/lib/active_record/migration/command_recorder.rb +96 -44
 - data/lib/active_record/migration/compatibility.rb +246 -64
 - data/lib/active_record/migration/join_table.rb +1 -2
 - data/lib/active_record/migration.rb +266 -187
 - data/lib/active_record/model_schema.rb +165 -52
 - data/lib/active_record/nested_attributes.rb +17 -19
 - data/lib/active_record/no_touching.rb +11 -4
 - data/lib/active_record/null_relation.rb +2 -7
 - data/lib/active_record/persistence.rb +467 -92
 - data/lib/active_record/query_cache.rb +21 -4
 - data/lib/active_record/query_logs.rb +138 -0
 - data/lib/active_record/querying.rb +51 -24
 - data/lib/active_record/railtie.rb +224 -57
 - data/lib/active_record/railties/console_sandbox.rb +2 -4
 - data/lib/active_record/railties/controller_runtime.rb +31 -36
 - data/lib/active_record/railties/databases.rake +369 -101
 - data/lib/active_record/readonly_attributes.rb +15 -0
 - data/lib/active_record/reflection.rb +170 -137
 - data/lib/active_record/relation/batches/batch_enumerator.rb +44 -14
 - data/lib/active_record/relation/batches.rb +46 -37
 - data/lib/active_record/relation/calculations.rb +168 -96
 - data/lib/active_record/relation/delegation.rb +37 -52
 - data/lib/active_record/relation/finder_methods.rb +79 -58
 - data/lib/active_record/relation/from_clause.rb +5 -1
 - data/lib/active_record/relation/merger.rb +50 -51
 - data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
 - data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
 - data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
 - data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
 - data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
 - data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
 - data/lib/active_record/relation/predicate_builder.rb +58 -46
 - data/lib/active_record/relation/query_attribute.rb +9 -10
 - data/lib/active_record/relation/query_methods.rb +685 -208
 - data/lib/active_record/relation/record_fetch_warning.rb +9 -11
 - data/lib/active_record/relation/spawn_methods.rb +10 -10
 - data/lib/active_record/relation/where_clause.rb +108 -64
 - data/lib/active_record/relation.rb +515 -151
 - data/lib/active_record/result.rb +78 -42
 - data/lib/active_record/runtime_registry.rb +9 -13
 - data/lib/active_record/sanitization.rb +29 -44
 - data/lib/active_record/schema.rb +37 -31
 - data/lib/active_record/schema_dumper.rb +74 -23
 - data/lib/active_record/schema_migration.rb +7 -9
 - data/lib/active_record/scoping/default.rb +62 -17
 - data/lib/active_record/scoping/named.rb +17 -32
 - data/lib/active_record/scoping.rb +70 -41
 - data/lib/active_record/secure_token.rb +16 -8
 - data/lib/active_record/serialization.rb +6 -4
 - data/lib/active_record/signed_id.rb +116 -0
 - data/lib/active_record/statement_cache.rb +49 -6
 - data/lib/active_record/store.rb +88 -9
 - data/lib/active_record/suppressor.rb +13 -17
 - data/lib/active_record/table_metadata.rb +42 -43
 - data/lib/active_record/tasks/database_tasks.rb +352 -94
 - data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
 - data/lib/active_record/tasks/postgresql_database_tasks.rb +41 -39
 - data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
 - data/lib/active_record/test_databases.rb +24 -0
 - data/lib/active_record/test_fixtures.rb +287 -0
 - data/lib/active_record/timestamp.rb +44 -34
 - data/lib/active_record/touch_later.rb +23 -22
 - data/lib/active_record/transactions.rb +67 -128
 - data/lib/active_record/translation.rb +3 -3
 - data/lib/active_record/type/adapter_specific_registry.rb +34 -19
 - data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
 - data/lib/active_record/type/internal/timezone.rb +2 -2
 - data/lib/active_record/type/serialized.rb +7 -4
 - data/lib/active_record/type/time.rb +10 -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 +9 -5
 - data/lib/active_record/type_caster/connection.rb +15 -15
 - data/lib/active_record/type_caster/map.rb +8 -8
 - data/lib/active_record/validations/associated.rb +2 -3
 - data/lib/active_record/validations/numericality.rb +35 -0
 - data/lib/active_record/validations/uniqueness.rb +39 -31
 - data/lib/active_record/validations.rb +4 -3
 - data/lib/active_record.rb +209 -32
 - data/lib/arel/alias_predication.rb +9 -0
 - data/lib/arel/attributes/attribute.rb +33 -0
 - data/lib/arel/collectors/bind.rb +29 -0
 - data/lib/arel/collectors/composite.rb +39 -0
 - data/lib/arel/collectors/plain_string.rb +20 -0
 - data/lib/arel/collectors/sql_string.rb +27 -0
 - data/lib/arel/collectors/substitute_binds.rb +35 -0
 - data/lib/arel/crud.rb +48 -0
 - data/lib/arel/delete_manager.rb +32 -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/filter_predications.rb +9 -0
 - data/lib/arel/insert_manager.rb +48 -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 +126 -0
 - data/lib/arel/nodes/bind_param.rb +44 -0
 - data/lib/arel/nodes/case.rb +55 -0
 - data/lib/arel/nodes/casted.rb +62 -0
 - data/lib/arel/nodes/comment.rb +29 -0
 - data/lib/arel/nodes/count.rb +12 -0
 - data/lib/arel/nodes/delete_statement.rb +44 -0
 - data/lib/arel/nodes/descending.rb +23 -0
 - data/lib/arel/nodes/equality.rb +15 -0
 - data/lib/arel/nodes/extract.rb +24 -0
 - data/lib/arel/nodes/false.rb +16 -0
 - data/lib/arel/nodes/filter.rb +10 -0
 - data/lib/arel/nodes/full_outer_join.rb +8 -0
 - data/lib/arel/nodes/function.rb +45 -0
 - data/lib/arel/nodes/grouping.rb +11 -0
 - data/lib/arel/nodes/homogeneous_in.rb +76 -0
 - data/lib/arel/nodes/in.rb +15 -0
 - data/lib/arel/nodes/infix_operation.rb +92 -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 +51 -0
 - data/lib/arel/nodes/node_expression.rb +13 -0
 - data/lib/arel/nodes/ordering.rb +27 -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 +19 -0
 - data/lib/arel/nodes/string_join.rb +11 -0
 - data/lib/arel/nodes/table_alias.rb +31 -0
 - data/lib/arel/nodes/terminal.rb +16 -0
 - data/lib/arel/nodes/true.rb +16 -0
 - data/lib/arel/nodes/unary.rb +44 -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 +46 -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 +71 -0
 - data/lib/arel/order_predications.rb +13 -0
 - data/lib/arel/predications.rb +258 -0
 - data/lib/arel/select_manager.rb +276 -0
 - data/lib/arel/table.rb +117 -0
 - data/lib/arel/tree_manager.rb +60 -0
 - data/lib/arel/update_manager.rb +48 -0
 - data/lib/arel/visitors/dot.rb +298 -0
 - data/lib/arel/visitors/mysql.rb +99 -0
 - data/lib/arel/visitors/postgresql.rb +110 -0
 - data/lib/arel/visitors/sqlite.rb +38 -0
 - data/lib/arel/visitors/to_sql.rb +955 -0
 - data/lib/arel/visitors/visitor.rb +45 -0
 - data/lib/arel/visitors.rb +13 -0
 - data/lib/arel/window_predications.rb +9 -0
 - data/lib/arel.rb +55 -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 +3 -5
 - data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
 - data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
 - data/lib/rails/generators/active_record/migration.rb +19 -2
 - data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
 - 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 +10 -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 +162 -32
 - data/lib/active_record/attribute_decorators.rb +0 -90
 - data/lib/active_record/collection_cache_key.rb +0 -53
 - data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
 - data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
 - data/lib/active_record/define_callbacks.rb +0 -22
 - data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
 - data/lib/active_record/relation/where_clause_factory.rb +0 -34
 
| 
         @@ -2,39 +2,6 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveRecord::Associations::Builder # :nodoc:
         
     | 
| 
       4 
4 
     | 
    
         
             
              class HasAndBelongsToMany # :nodoc:
         
     | 
| 
       5 
     | 
    
         
            -
                class JoinTableResolver # :nodoc:
         
     | 
| 
       6 
     | 
    
         
            -
                  KnownTable = Struct.new :join_table
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
                  class KnownClass # :nodoc:
         
     | 
| 
       9 
     | 
    
         
            -
                    def initialize(lhs_class, rhs_class_name)
         
     | 
| 
       10 
     | 
    
         
            -
                      @lhs_class      = lhs_class
         
     | 
| 
       11 
     | 
    
         
            -
                      @rhs_class_name = rhs_class_name
         
     | 
| 
       12 
     | 
    
         
            -
                      @join_table     = nil
         
     | 
| 
       13 
     | 
    
         
            -
                    end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                    def join_table
         
     | 
| 
       16 
     | 
    
         
            -
                      @join_table ||= [@lhs_class.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
         
     | 
| 
       17 
     | 
    
         
            -
                    end
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
                    private
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
                      def klass
         
     | 
| 
       22 
     | 
    
         
            -
                        @lhs_class.send(:compute_type, @rhs_class_name)
         
     | 
| 
       23 
     | 
    
         
            -
                      end
         
     | 
| 
       24 
     | 
    
         
            -
                  end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                  def self.build(lhs_class, name, options)
         
     | 
| 
       27 
     | 
    
         
            -
                    if options[:join_table]
         
     | 
| 
       28 
     | 
    
         
            -
                      KnownTable.new options[:join_table].to_s
         
     | 
| 
       29 
     | 
    
         
            -
                    else
         
     | 
| 
       30 
     | 
    
         
            -
                      class_name = options.fetch(:class_name) {
         
     | 
| 
       31 
     | 
    
         
            -
                        name.to_s.camelize.singularize
         
     | 
| 
       32 
     | 
    
         
            -
                      }
         
     | 
| 
       33 
     | 
    
         
            -
                      KnownClass.new lhs_class, class_name.to_s
         
     | 
| 
       34 
     | 
    
         
            -
                    end
         
     | 
| 
       35 
     | 
    
         
            -
                  end
         
     | 
| 
       36 
     | 
    
         
            -
                end
         
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
5 
     | 
    
         
             
                attr_reader :lhs_model, :association_name, :options
         
     | 
| 
       39 
6 
     | 
    
         | 
| 
       40 
7 
     | 
    
         
             
                def initialize(association_name, lhs_model, options)
         
     | 
| 
         @@ -44,8 +11,6 @@ module ActiveRecord::Associations::Builder # :nodoc: 
     | 
|
| 
       44 
11 
     | 
    
         
             
                end
         
     | 
| 
       45 
12 
     | 
    
         | 
| 
       46 
13 
     | 
    
         
             
                def through_model
         
     | 
| 
       47 
     | 
    
         
            -
                  habtm = JoinTableResolver.build lhs_model, association_name, options
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
14 
     | 
    
         
             
                  join_model = Class.new(ActiveRecord::Base) {
         
     | 
| 
       50 
15 
     | 
    
         
             
                    class << self
         
     | 
| 
       51 
16 
     | 
    
         
             
                      attr_accessor :left_model
         
     | 
| 
         @@ -56,7 +21,9 @@ module ActiveRecord::Associations::Builder # :nodoc: 
     | 
|
| 
       56 
21 
     | 
    
         
             
                    end
         
     | 
| 
       57 
22 
     | 
    
         | 
| 
       58 
23 
     | 
    
         
             
                    def self.table_name
         
     | 
| 
       59 
     | 
    
         
            -
                       
     | 
| 
      
 24 
     | 
    
         
            +
                      # Table name needs to be resolved lazily
         
     | 
| 
      
 25 
     | 
    
         
            +
                      # because RHS class might not have been loaded
         
     | 
| 
      
 26 
     | 
    
         
            +
                      @table_name ||= table_name_resolver.call
         
     | 
| 
       60 
27 
     | 
    
         
             
                    end
         
     | 
| 
       61 
28 
     | 
    
         | 
| 
       62 
29 
     | 
    
         
             
                    def self.compute_type(class_name)
         
     | 
| 
         @@ -79,14 +46,13 @@ module ActiveRecord::Associations::Builder # :nodoc: 
     | 
|
| 
       79 
46 
     | 
    
         
             
                    end
         
     | 
| 
       80 
47 
     | 
    
         | 
| 
       81 
48 
     | 
    
         
             
                    private
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
49 
     | 
    
         
             
                      def self.suppress_composite_primary_key(pk)
         
     | 
| 
       84 
50 
     | 
    
         
             
                        pk unless pk.is_a?(Array)
         
     | 
| 
       85 
51 
     | 
    
         
             
                      end
         
     | 
| 
       86 
52 
     | 
    
         
             
                  }
         
     | 
| 
       87 
53 
     | 
    
         | 
| 
       88 
54 
     | 
    
         
             
                  join_model.name                = "HABTM_#{association_name.to_s.camelize}"
         
     | 
| 
       89 
     | 
    
         
            -
                  join_model.table_name_resolver =  
     | 
| 
      
 55 
     | 
    
         
            +
                  join_model.table_name_resolver = -> { table_name }
         
     | 
| 
       90 
56 
     | 
    
         
             
                  join_model.left_model          = lhs_model
         
     | 
| 
       91 
57 
     | 
    
         | 
| 
       92 
58 
     | 
    
         
             
                  join_model.add_left_association :left_side, anonymous_class: lhs_model
         
     | 
| 
         @@ -96,7 +62,7 @@ module ActiveRecord::Associations::Builder # :nodoc: 
     | 
|
| 
       96 
62 
     | 
    
         | 
| 
       97 
63 
     | 
    
         
             
                def middle_reflection(join_model)
         
     | 
| 
       98 
64 
     | 
    
         
             
                  middle_name = [lhs_model.name.downcase.pluralize,
         
     | 
| 
       99 
     | 
    
         
            -
                                 association_name].join("_" 
     | 
| 
      
 65 
     | 
    
         
            +
                                 association_name.to_s].sort.join("_").gsub("::", "_").to_sym
         
     | 
| 
       100 
66 
     | 
    
         
             
                  middle_options = middle_options join_model
         
     | 
| 
       101 
67 
     | 
    
         | 
| 
       102 
68 
     | 
    
         
             
                  HasMany.create_reflection(lhs_model,
         
     | 
| 
         @@ -106,17 +72,27 @@ module ActiveRecord::Associations::Builder # :nodoc: 
     | 
|
| 
       106 
72 
     | 
    
         
             
                end
         
     | 
| 
       107 
73 
     | 
    
         | 
| 
       108 
74 
     | 
    
         
             
                private
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
75 
     | 
    
         
             
                  def middle_options(join_model)
         
     | 
| 
       111 
76 
     | 
    
         
             
                    middle_options = {}
         
     | 
| 
       112 
77 
     | 
    
         
             
                    middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
         
     | 
| 
       113 
     | 
    
         
            -
                    middle_options[:source] = join_model.left_reflection.name
         
     | 
| 
       114 
78 
     | 
    
         
             
                    if options.key? :foreign_key
         
     | 
| 
       115 
79 
     | 
    
         
             
                      middle_options[:foreign_key] = options[:foreign_key]
         
     | 
| 
       116 
80 
     | 
    
         
             
                    end
         
     | 
| 
       117 
81 
     | 
    
         
             
                    middle_options
         
     | 
| 
       118 
82 
     | 
    
         
             
                  end
         
     | 
| 
       119 
83 
     | 
    
         | 
| 
      
 84 
     | 
    
         
            +
                  def table_name
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if options[:join_table]
         
     | 
| 
      
 86 
     | 
    
         
            +
                      options[:join_table].to_s
         
     | 
| 
      
 87 
     | 
    
         
            +
                    else
         
     | 
| 
      
 88 
     | 
    
         
            +
                      class_name = options.fetch(:class_name) {
         
     | 
| 
      
 89 
     | 
    
         
            +
                        association_name.to_s.camelize.singularize
         
     | 
| 
      
 90 
     | 
    
         
            +
                      }
         
     | 
| 
      
 91 
     | 
    
         
            +
                      klass = lhs_model.send(:compute_type, class_name.to_s)
         
     | 
| 
      
 92 
     | 
    
         
            +
                      [lhs_model.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
       120 
96 
     | 
    
         
             
                  def belongs_to_options(options)
         
     | 
| 
       121 
97 
     | 
    
         
             
                    rhs_options = {}
         
     | 
| 
       122 
98 
     | 
    
         | 
| 
         @@ -1,17 +1,24 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveRecord::Associations::Builder # :nodoc:
         
     | 
| 
       4 
     | 
    
         
            -
              class HasMany < CollectionAssociation  
     | 
| 
      
 4 
     | 
    
         
            +
              class HasMany < CollectionAssociation # :nodoc:
         
     | 
| 
       5 
5 
     | 
    
         
             
                def self.macro
         
     | 
| 
       6 
6 
     | 
    
         
             
                  :has_many
         
     | 
| 
       7 
7 
     | 
    
         
             
                end
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
                def self.valid_options(options)
         
     | 
| 
       10 
     | 
    
         
            -
                  super + [: 
     | 
| 
      
 10 
     | 
    
         
            +
                  valid = super + [:counter_cache, :join_table, :index_errors]
         
     | 
| 
      
 11 
     | 
    
         
            +
                  valid += [:as, :foreign_type] if options[:as]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  valid += [:through, :source, :source_type] if options[:through]
         
     | 
| 
      
 13 
     | 
    
         
            +
                  valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
         
     | 
| 
      
 14 
     | 
    
         
            +
                  valid += [:disable_joins] if options[:disable_joins] && options[:through]
         
     | 
| 
      
 15 
     | 
    
         
            +
                  valid
         
     | 
| 
       11 
16 
     | 
    
         
             
                end
         
     | 
| 
       12 
17 
     | 
    
         | 
| 
       13 
18 
     | 
    
         
             
                def self.valid_dependent_options
         
     | 
| 
       14 
     | 
    
         
            -
                  [:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  [:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception, :destroy_async]
         
     | 
| 
       15 
20 
     | 
    
         
             
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                private_class_method :macro, :valid_options, :valid_dependent_options
         
     | 
| 
       16 
23 
     | 
    
         
             
              end
         
     | 
| 
       17 
24 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,19 +1,27 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveRecord::Associations::Builder # :nodoc:
         
     | 
| 
       4 
     | 
    
         
            -
              class HasOne < SingularAssociation  
     | 
| 
      
 4 
     | 
    
         
            +
              class HasOne < SingularAssociation # :nodoc:
         
     | 
| 
       5 
5 
     | 
    
         
             
                def self.macro
         
     | 
| 
       6 
6 
     | 
    
         
             
                  :has_one
         
     | 
| 
       7 
7 
     | 
    
         
             
                end
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
                def self.valid_options(options)
         
     | 
| 
       10 
     | 
    
         
            -
                  valid = super 
     | 
| 
      
 10 
     | 
    
         
            +
                  valid = super
         
     | 
| 
      
 11 
     | 
    
         
            +
                  valid += [:as, :foreign_type] if options[:as]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
         
     | 
| 
       11 
13 
     | 
    
         
             
                  valid += [:through, :source, :source_type] if options[:through]
         
     | 
| 
      
 14 
     | 
    
         
            +
                  valid += [:disable_joins] if options[:disable_joins] && options[:through]
         
     | 
| 
       12 
15 
     | 
    
         
             
                  valid
         
     | 
| 
       13 
16 
     | 
    
         
             
                end
         
     | 
| 
       14 
17 
     | 
    
         | 
| 
       15 
18 
     | 
    
         
             
                def self.valid_dependent_options
         
     | 
| 
       16 
     | 
    
         
            -
                  [:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  [:destroy, :destroy_async, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def self.define_callbacks(model, reflection)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  super
         
     | 
| 
      
 24 
     | 
    
         
            +
                  add_touch_callbacks(model, reflection) if reflection.options[:touch]
         
     | 
| 
       17 
25 
     | 
    
         
             
                end
         
     | 
| 
       18 
26 
     | 
    
         | 
| 
       19 
27 
     | 
    
         
             
                def self.add_destroy_callbacks(model, reflection)
         
     | 
| 
         @@ -26,5 +34,29 @@ module ActiveRecord::Associations::Builder # :nodoc: 
     | 
|
| 
       26 
34 
     | 
    
         
             
                    model.validates_presence_of reflection.name, message: :required
         
     | 
| 
       27 
35 
     | 
    
         
             
                  end
         
     | 
| 
       28 
36 
     | 
    
         
             
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def self.touch_record(record, name, touch)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  instance = record.send(name)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  if instance&.persisted?
         
     | 
| 
      
 42 
     | 
    
         
            +
                    touch != true ?
         
     | 
| 
      
 43 
     | 
    
         
            +
                      instance.touch(touch) : instance.touch
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def self.add_touch_callbacks(model, reflection)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  name  = reflection.name
         
     | 
| 
      
 49 
     | 
    
         
            +
                  touch = reflection.options[:touch]
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  callback = -> (record) { HasOne.touch_record(record, name, touch) }
         
     | 
| 
      
 52 
     | 
    
         
            +
                  model.after_create callback, if: :saved_changes?
         
     | 
| 
      
 53 
     | 
    
         
            +
                  model.after_create_commit { association(name).reset_negative_cache }
         
     | 
| 
      
 54 
     | 
    
         
            +
                  model.after_update callback, if: :saved_changes?
         
     | 
| 
      
 55 
     | 
    
         
            +
                  model.after_destroy callback
         
     | 
| 
      
 56 
     | 
    
         
            +
                  model.after_touch callback
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                private_class_method :macro, :valid_options, :valid_dependent_options, :add_destroy_callbacks,
         
     | 
| 
      
 60 
     | 
    
         
            +
                  :define_callbacks, :define_validations, :add_touch_callbacks
         
     | 
| 
       29 
61 
     | 
    
         
             
              end
         
     | 
| 
       30 
62 
     | 
    
         
             
            end
         
     | 
| 
         @@ -3,9 +3,9 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            # This class is inherited by the has_one and belongs_to association classes
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module ActiveRecord::Associations::Builder # :nodoc:
         
     | 
| 
       6 
     | 
    
         
            -
              class SingularAssociation < Association  
     | 
| 
      
 6 
     | 
    
         
            +
              class SingularAssociation < Association # :nodoc:
         
     | 
| 
       7 
7 
     | 
    
         
             
                def self.valid_options(options)
         
     | 
| 
       8 
     | 
    
         
            -
                  super + [: 
     | 
| 
      
 8 
     | 
    
         
            +
                  super + [:required, :touch]
         
     | 
| 
       9 
9 
     | 
    
         
             
                end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
                def self.define_accessors(model, reflection)
         
     | 
| 
         @@ -13,7 +13,7 @@ module ActiveRecord::Associations::Builder # :nodoc: 
     | 
|
| 
       13 
13 
     | 
    
         
             
                  mixin = model.generated_association_methods
         
     | 
| 
       14 
14 
     | 
    
         
             
                  name = reflection.name
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
                  define_constructors(mixin, name)  
     | 
| 
      
 16 
     | 
    
         
            +
                  define_constructors(mixin, name) unless reflection.polymorphic?
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                  mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
         
     | 
| 
       19 
19 
     | 
    
         
             
                    def reload_#{name}
         
     | 
| 
         @@ -38,5 +38,7 @@ module ActiveRecord::Associations::Builder # :nodoc: 
     | 
|
| 
       38 
38 
     | 
    
         
             
                    end
         
     | 
| 
       39 
39 
     | 
    
         
             
                  CODE
         
     | 
| 
       40 
40 
     | 
    
         
             
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                private_class_method :valid_options, :define_accessors, :define_constructors
         
     | 
| 
       41 
43 
     | 
    
         
             
              end
         
     | 
| 
       42 
44 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,5 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require "active_support/core_ext/enumerable"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       3 
5 
     | 
    
         
             
            module ActiveRecord
         
     | 
| 
       4 
6 
     | 
    
         
             
              module Associations
         
     | 
| 
       5 
7 
     | 
    
         
             
                # = Active Record Association Collection
         
     | 
| 
         @@ -25,9 +27,11 @@ module ActiveRecord 
     | 
|
| 
       25 
27 
     | 
    
         
             
                #
         
     | 
| 
       26 
28 
     | 
    
         
             
                # If you need to work on all current children, new and existing records,
         
     | 
| 
       27 
29 
     | 
    
         
             
                # +load_target+ and the +loaded+ flag are your friends.
         
     | 
| 
       28 
     | 
    
         
            -
                class CollectionAssociation < Association  
     | 
| 
      
 30 
     | 
    
         
            +
                class CollectionAssociation < Association # :nodoc:
         
     | 
| 
       29 
31 
     | 
    
         
             
                  # Implements the reader method, e.g. foo.items for Foo.has_many :items
         
     | 
| 
       30 
32 
     | 
    
         
             
                  def reader
         
     | 
| 
      
 33 
     | 
    
         
            +
                    ensure_klass_exists!
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
       31 
35 
     | 
    
         
             
                    if stale_target?
         
     | 
| 
       32 
36 
     | 
    
         
             
                      reload
         
     | 
| 
       33 
37 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -56,7 +60,7 @@ module ActiveRecord 
     | 
|
| 
       56 
60 
     | 
    
         
             
                  def ids_writer(ids)
         
     | 
| 
       57 
61 
     | 
    
         
             
                    primary_key = reflection.association_primary_key
         
     | 
| 
       58 
62 
     | 
    
         
             
                    pk_type = klass.type_for_attribute(primary_key)
         
     | 
| 
       59 
     | 
    
         
            -
                    ids = Array(ids). 
     | 
| 
      
 63 
     | 
    
         
            +
                    ids = Array(ids).compact_blank
         
     | 
| 
       60 
64 
     | 
    
         
             
                    ids.map! { |i| pk_type.cast(i) }
         
     | 
| 
       61 
65 
     | 
    
         | 
| 
       62 
66 
     | 
    
         
             
                    records = klass.where(primary_key => ids).index_by do |r|
         
     | 
| 
         @@ -75,6 +79,7 @@ module ActiveRecord 
     | 
|
| 
       75 
79 
     | 
    
         
             
                  def reset
         
     | 
| 
       76 
80 
     | 
    
         
             
                    super
         
     | 
| 
       77 
81 
     | 
    
         
             
                    @target = []
         
     | 
| 
      
 82 
     | 
    
         
            +
                    @replaced_or_added_targets = Set.new
         
     | 
| 
       78 
83 
     | 
    
         
             
                    @association_ids = nil
         
     | 
| 
       79 
84 
     | 
    
         
             
                  end
         
     | 
| 
       80 
85 
     | 
    
         | 
| 
         @@ -101,11 +106,11 @@ module ActiveRecord 
     | 
|
| 
       101 
106 
     | 
    
         
             
                    end
         
     | 
| 
       102 
107 
     | 
    
         
             
                  end
         
     | 
| 
       103 
108 
     | 
    
         | 
| 
       104 
     | 
    
         
            -
                  def build(attributes =  
     | 
| 
      
 109 
     | 
    
         
            +
                  def build(attributes = nil, &block)
         
     | 
| 
       105 
110 
     | 
    
         
             
                    if attributes.is_a?(Array)
         
     | 
| 
       106 
111 
     | 
    
         
             
                      attributes.collect { |attr| build(attr, &block) }
         
     | 
| 
       107 
112 
     | 
    
         
             
                    else
         
     | 
| 
       108 
     | 
    
         
            -
                      add_to_target(build_record(attributes, &block))
         
     | 
| 
      
 113 
     | 
    
         
            +
                      add_to_target(build_record(attributes, &block), replace: true)
         
     | 
| 
       109 
114 
     | 
    
         
             
                    end
         
     | 
| 
       110 
115 
     | 
    
         
             
                  end
         
     | 
| 
       111 
116 
     | 
    
         | 
| 
         @@ -121,21 +126,6 @@ module ActiveRecord 
     | 
|
| 
       121 
126 
     | 
    
         
             
                    end
         
     | 
| 
       122 
127 
     | 
    
         
             
                  end
         
     | 
| 
       123 
128 
     | 
    
         | 
| 
       124 
     | 
    
         
            -
                  # Starts a transaction in the association class's database connection.
         
     | 
| 
       125 
     | 
    
         
            -
                  #
         
     | 
| 
       126 
     | 
    
         
            -
                  #   class Author < ActiveRecord::Base
         
     | 
| 
       127 
     | 
    
         
            -
                  #     has_many :books
         
     | 
| 
       128 
     | 
    
         
            -
                  #   end
         
     | 
| 
       129 
     | 
    
         
            -
                  #
         
     | 
| 
       130 
     | 
    
         
            -
                  #   Author.first.books.transaction do
         
     | 
| 
       131 
     | 
    
         
            -
                  #     # same effect as calling Book.transaction
         
     | 
| 
       132 
     | 
    
         
            -
                  #   end
         
     | 
| 
       133 
     | 
    
         
            -
                  def transaction(*args)
         
     | 
| 
       134 
     | 
    
         
            -
                    reflection.klass.transaction(*args) do
         
     | 
| 
       135 
     | 
    
         
            -
                      yield
         
     | 
| 
       136 
     | 
    
         
            -
                    end
         
     | 
| 
       137 
     | 
    
         
            -
                  end
         
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
129 
     | 
    
         
             
                  # Removes all records from the association without calling callbacks
         
     | 
| 
       140 
130 
     | 
    
         
             
                  # on the associated records. It honors the +:dependent+ option. However
         
     | 
| 
       141 
131 
     | 
    
         
             
                  # if the +:dependent+ value is +:destroy+ then in that case the +:delete_all+
         
     | 
| 
         @@ -211,9 +201,11 @@ module ActiveRecord 
     | 
|
| 
       211 
201 
     | 
    
         
             
                  def size
         
     | 
| 
       212 
202 
     | 
    
         
             
                    if !find_target? || loaded?
         
     | 
| 
       213 
203 
     | 
    
         
             
                      target.size
         
     | 
| 
      
 204 
     | 
    
         
            +
                    elsif @association_ids
         
     | 
| 
      
 205 
     | 
    
         
            +
                      @association_ids.size
         
     | 
| 
       214 
206 
     | 
    
         
             
                    elsif !association_scope.group_values.empty?
         
     | 
| 
       215 
207 
     | 
    
         
             
                      load_target.size
         
     | 
| 
       216 
     | 
    
         
            -
                    elsif !association_scope.distinct_value && target. 
     | 
| 
      
 208 
     | 
    
         
            +
                    elsif !association_scope.distinct_value && !target.empty?
         
     | 
| 
       217 
209 
     | 
    
         
             
                      unsaved_records = target.select(&:new_record?)
         
     | 
| 
       218 
210 
     | 
    
         
             
                      unsaved_records.size + count_records
         
     | 
| 
       219 
211 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -226,14 +218,14 @@ module ActiveRecord 
     | 
|
| 
       226 
218 
     | 
    
         
             
                  # If the collection has been loaded
         
     | 
| 
       227 
219 
     | 
    
         
             
                  # it is equivalent to <tt>collection.size.zero?</tt>. If the
         
     | 
| 
       228 
220 
     | 
    
         
             
                  # collection has not been loaded, it is equivalent to
         
     | 
| 
       229 
     | 
    
         
            -
                  # <tt 
     | 
| 
      
 221 
     | 
    
         
            +
                  # <tt>!collection.exists?</tt>. If the collection has not already been
         
     | 
| 
       230 
222 
     | 
    
         
             
                  # loaded and you are going to fetch the records anyway it is better to
         
     | 
| 
       231 
223 
     | 
    
         
             
                  # check <tt>collection.length.zero?</tt>.
         
     | 
| 
       232 
224 
     | 
    
         
             
                  def empty?
         
     | 
| 
       233 
     | 
    
         
            -
                    if loaded?
         
     | 
| 
      
 225 
     | 
    
         
            +
                    if loaded? || @association_ids || reflection.has_cached_counter?
         
     | 
| 
       234 
226 
     | 
    
         
             
                      size.zero?
         
     | 
| 
       235 
227 
     | 
    
         
             
                    else
         
     | 
| 
       236 
     | 
    
         
            -
                       
     | 
| 
      
 228 
     | 
    
         
            +
                      target.empty? && !scope.exists?
         
     | 
| 
       237 
229 
     | 
    
         
             
                    end
         
     | 
| 
       238 
230 
     | 
    
         
             
                  end
         
     | 
| 
       239 
231 
     | 
    
         | 
| 
         @@ -276,11 +268,21 @@ module ActiveRecord 
     | 
|
| 
       276 
268 
     | 
    
         
             
                    target
         
     | 
| 
       277 
269 
     | 
    
         
             
                  end
         
     | 
| 
       278 
270 
     | 
    
         | 
| 
       279 
     | 
    
         
            -
                  def add_to_target(record, skip_callbacks  
     | 
| 
       280 
     | 
    
         
            -
                     
     | 
| 
       281 
     | 
    
         
            -
             
     | 
| 
      
 271 
     | 
    
         
            +
                  def add_to_target(record, skip_callbacks: false, replace: false, &block)
         
     | 
| 
      
 272 
     | 
    
         
            +
                    replace_on_target(record, skip_callbacks, replace: replace || association_scope.distinct_value, &block)
         
     | 
| 
      
 273 
     | 
    
         
            +
                  end
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
                  def target=(record)
         
     | 
| 
      
 276 
     | 
    
         
            +
                    return super unless reflection.klass.has_many_inversing
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
                    case record
         
     | 
| 
      
 279 
     | 
    
         
            +
                    when nil
         
     | 
| 
      
 280 
     | 
    
         
            +
                      # It's not possible to remove the record from the inverse association.
         
     | 
| 
      
 281 
     | 
    
         
            +
                    when Array
         
     | 
| 
      
 282 
     | 
    
         
            +
                      super
         
     | 
| 
      
 283 
     | 
    
         
            +
                    else
         
     | 
| 
      
 284 
     | 
    
         
            +
                      replace_on_target(record, true, replace: true, inversing: true)
         
     | 
| 
       282 
285 
     | 
    
         
             
                    end
         
     | 
| 
       283 
     | 
    
         
            -
                    replace_on_target(record, index, skip_callbacks, &block)
         
     | 
| 
       284 
286 
     | 
    
         
             
                  end
         
     | 
| 
       285 
287 
     | 
    
         | 
| 
       286 
288 
     | 
    
         
             
                  def scope
         
     | 
| 
         @@ -295,26 +297,15 @@ module ActiveRecord 
     | 
|
| 
       295 
297 
     | 
    
         | 
| 
       296 
298 
     | 
    
         
             
                  def find_from_target?
         
     | 
| 
       297 
299 
     | 
    
         
             
                    loaded? ||
         
     | 
| 
      
 300 
     | 
    
         
            +
                      owner.strict_loading? ||
         
     | 
| 
      
 301 
     | 
    
         
            +
                      reflection.strict_loading? ||
         
     | 
| 
       298 
302 
     | 
    
         
             
                      owner.new_record? ||
         
     | 
| 
       299 
303 
     | 
    
         
             
                      target.any? { |record| record.new_record? || record.changed? }
         
     | 
| 
       300 
304 
     | 
    
         
             
                  end
         
     | 
| 
       301 
305 
     | 
    
         | 
| 
       302 
306 
     | 
    
         
             
                  private
         
     | 
| 
       303 
     | 
    
         
            -
             
     | 
| 
       304 
     | 
    
         
            -
             
     | 
| 
       305 
     | 
    
         
            -
                      scope = self.scope
         
     | 
| 
       306 
     | 
    
         
            -
                      return scope.to_a if skip_statement_cache?(scope)
         
     | 
| 
       307 
     | 
    
         
            -
             
     | 
| 
       308 
     | 
    
         
            -
                      conn = klass.connection
         
     | 
| 
       309 
     | 
    
         
            -
                      sc = reflection.association_scope_cache(conn, owner) do |params|
         
     | 
| 
       310 
     | 
    
         
            -
                        as = AssociationScope.create { params.bind }
         
     | 
| 
       311 
     | 
    
         
            -
                        target_scope.merge!(as.scope(self))
         
     | 
| 
       312 
     | 
    
         
            -
                      end
         
     | 
| 
       313 
     | 
    
         
            -
             
     | 
| 
       314 
     | 
    
         
            -
                      binds = AssociationScope.get_bind_values(owner, reflection.chain)
         
     | 
| 
       315 
     | 
    
         
            -
                      sc.execute(binds, conn) do |record|
         
     | 
| 
       316 
     | 
    
         
            -
                        set_inverse_instance(record)
         
     | 
| 
       317 
     | 
    
         
            -
                      end
         
     | 
| 
      
 307 
     | 
    
         
            +
                    def transaction(&block)
         
     | 
| 
      
 308 
     | 
    
         
            +
                      reflection.klass.transaction(&block)
         
     | 
| 
       318 
309 
     | 
    
         
             
                    end
         
     | 
| 
       319 
310 
     | 
    
         | 
| 
       320 
311 
     | 
    
         
             
                    # We have some records loaded from the database (persisted) and some that are
         
     | 
| 
         @@ -344,12 +335,12 @@ module ActiveRecord 
     | 
|
| 
       344 
335 
     | 
    
         
             
                        end
         
     | 
| 
       345 
336 
     | 
    
         
             
                      end
         
     | 
| 
       346 
337 
     | 
    
         | 
| 
       347 
     | 
    
         
            -
                      persisted + memory
         
     | 
| 
      
 338 
     | 
    
         
            +
                      persisted + memory.reject(&:persisted?)
         
     | 
| 
       348 
339 
     | 
    
         
             
                    end
         
     | 
| 
       349 
340 
     | 
    
         | 
| 
       350 
341 
     | 
    
         
             
                    def _create_record(attributes, raise = false, &block)
         
     | 
| 
       351 
342 
     | 
    
         
             
                      unless owner.persisted?
         
     | 
| 
       352 
     | 
    
         
            -
                        raise ActiveRecord::RecordNotSaved 
     | 
| 
      
 343 
     | 
    
         
            +
                        raise ActiveRecord::RecordNotSaved.new("You cannot call create unless the parent is saved", owner)
         
     | 
| 
       353 
344 
     | 
    
         
             
                      end
         
     | 
| 
       354 
345 
     | 
    
         | 
| 
       355 
346 
     | 
    
         
             
                      if attributes.is_a?(Array)
         
     | 
| 
         @@ -393,10 +384,12 @@ module ActiveRecord 
     | 
|
| 
       393 
384 
     | 
    
         
             
                    end
         
     | 
| 
       394 
385 
     | 
    
         | 
| 
       395 
386 
     | 
    
         
             
                    def remove_records(existing_records, records, method)
         
     | 
| 
       396 
     | 
    
         
            -
                       
     | 
| 
      
 387 
     | 
    
         
            +
                      catch(:abort) do
         
     | 
| 
      
 388 
     | 
    
         
            +
                        records.each { |record| callback(:before_remove, record) }
         
     | 
| 
      
 389 
     | 
    
         
            +
                      end || return
         
     | 
| 
       397 
390 
     | 
    
         | 
| 
       398 
391 
     | 
    
         
             
                      delete_records(existing_records, method) if existing_records.any?
         
     | 
| 
       399 
     | 
    
         
            -
                       
     | 
| 
      
 392 
     | 
    
         
            +
                      @target -= records
         
     | 
| 
       400 
393 
     | 
    
         
             
                      @association_ids = nil
         
     | 
| 
       401 
394 
     | 
    
         | 
| 
       402 
395 
     | 
    
         
             
                      records.each { |record| callback(:after_remove, record) }
         
     | 
| 
         @@ -425,7 +418,7 @@ module ActiveRecord 
     | 
|
| 
       425 
418 
     | 
    
         
             
                      common_records = intersection(new_target, original_target)
         
     | 
| 
       426 
419 
     | 
    
         
             
                      common_records.each do |record|
         
     | 
| 
       427 
420 
     | 
    
         
             
                        skip_callbacks = true
         
     | 
| 
       428 
     | 
    
         
            -
                        replace_on_target(record,  
     | 
| 
      
 421 
     | 
    
         
            +
                        replace_on_target(record, skip_callbacks, replace: true)
         
     | 
| 
       429 
422 
     | 
    
         
             
                      end
         
     | 
| 
       430 
423 
     | 
    
         
             
                    end
         
     | 
| 
       431 
424 
     | 
    
         | 
| 
         @@ -448,8 +441,14 @@ module ActiveRecord 
     | 
|
| 
       448 
441 
     | 
    
         
             
                      records
         
     | 
| 
       449 
442 
     | 
    
         
             
                    end
         
     | 
| 
       450 
443 
     | 
    
         | 
| 
       451 
     | 
    
         
            -
                    def replace_on_target(record,  
     | 
| 
       452 
     | 
    
         
            -
                       
     | 
| 
      
 444 
     | 
    
         
            +
                    def replace_on_target(record, skip_callbacks, replace:, inversing: false)
         
     | 
| 
      
 445 
     | 
    
         
            +
                      if replace && (!record.new_record? || @replaced_or_added_targets.include?(record))
         
     | 
| 
      
 446 
     | 
    
         
            +
                        index = @target.index(record)
         
     | 
| 
      
 447 
     | 
    
         
            +
                      end
         
     | 
| 
      
 448 
     | 
    
         
            +
             
     | 
| 
      
 449 
     | 
    
         
            +
                      catch(:abort) do
         
     | 
| 
      
 450 
     | 
    
         
            +
                        callback(:before_add, record)
         
     | 
| 
      
 451 
     | 
    
         
            +
                      end || return unless skip_callbacks
         
     | 
| 
       453 
452 
     | 
    
         | 
| 
       454 
453 
     | 
    
         
             
                      set_inverse_instance(record)
         
     | 
| 
       455 
454 
     | 
    
         | 
| 
         @@ -457,6 +456,12 @@ module ActiveRecord 
     | 
|
| 
       457 
456 
     | 
    
         | 
| 
       458 
457 
     | 
    
         
             
                      yield(record) if block_given?
         
     | 
| 
       459 
458 
     | 
    
         | 
| 
      
 459 
     | 
    
         
            +
                      if !index && @replaced_or_added_targets.include?(record)
         
     | 
| 
      
 460 
     | 
    
         
            +
                        index = @target.index(record)
         
     | 
| 
      
 461 
     | 
    
         
            +
                      end
         
     | 
| 
      
 462 
     | 
    
         
            +
             
     | 
| 
      
 463 
     | 
    
         
            +
                      @replaced_or_added_targets << record if inversing || index || record.new_record?
         
     | 
| 
      
 464 
     | 
    
         
            +
             
     | 
| 
       460 
465 
     | 
    
         
             
                      if index
         
     | 
| 
       461 
466 
     | 
    
         
             
                        target[index] = record
         
     | 
| 
       462 
467 
     | 
    
         
             
                      elsif @_was_loaded || !loaded?
         
     | 
| 
         @@ -479,7 +484,11 @@ module ActiveRecord 
     | 
|
| 
       479 
484 
     | 
    
         | 
| 
       480 
485 
     | 
    
         
             
                    def callbacks_for(callback_name)
         
     | 
| 
       481 
486 
     | 
    
         
             
                      full_callback_name = "#{callback_name}_for_#{reflection.name}"
         
     | 
| 
       482 
     | 
    
         
            -
                      owner.class. 
     | 
| 
      
 487 
     | 
    
         
            +
                      if owner.class.respond_to?(full_callback_name)
         
     | 
| 
      
 488 
     | 
    
         
            +
                        owner.class.send(full_callback_name)
         
     | 
| 
      
 489 
     | 
    
         
            +
                      else
         
     | 
| 
      
 490 
     | 
    
         
            +
                        []
         
     | 
| 
      
 491 
     | 
    
         
            +
                      end
         
     | 
| 
       483 
492 
     | 
    
         
             
                    end
         
     | 
| 
       484 
493 
     | 
    
         | 
| 
       485 
494 
     | 
    
         
             
                    def include_in_memory?(record)
         
     | 
| 
         @@ -2,11 +2,8 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveRecord
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Associations
         
     | 
| 
       5 
     | 
    
         
            -
                #  
     | 
| 
       6 
     | 
    
         
            -
                #  
     | 
| 
       7 
     | 
    
         
            -
                # object, known as the <tt>@target</tt>. The kind of association any proxy is
         
     | 
| 
       8 
     | 
    
         
            -
                # about is available in <tt>@reflection</tt>. That's an instance of the class
         
     | 
| 
       9 
     | 
    
         
            -
                # ActiveRecord::Reflection::AssociationReflection.
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Collection proxies in Active Record are middlemen between an
         
     | 
| 
      
 6 
     | 
    
         
            +
                # <tt>association</tt>, and its <tt>target</tt> result set.
         
     | 
| 
       10 
7 
     | 
    
         
             
                #
         
     | 
| 
       11 
8 
     | 
    
         
             
                # For example, given
         
     | 
| 
       12 
9 
     | 
    
         
             
                #
         
     | 
| 
         @@ -16,21 +13,21 @@ module ActiveRecord 
     | 
|
| 
       16 
13 
     | 
    
         
             
                #
         
     | 
| 
       17 
14 
     | 
    
         
             
                #   blog = Blog.first
         
     | 
| 
       18 
15 
     | 
    
         
             
                #
         
     | 
| 
       19 
     | 
    
         
            -
                #  
     | 
| 
       20 
     | 
    
         
            -
                # <tt 
     | 
| 
       21 
     | 
    
         
            -
                #  
     | 
| 
      
 16 
     | 
    
         
            +
                # The collection proxy returned by <tt>blog.posts</tt> is built from a
         
     | 
| 
      
 17 
     | 
    
         
            +
                # <tt>:has_many</tt> <tt>association</tt>, and delegates to a collection
         
     | 
| 
      
 18 
     | 
    
         
            +
                # of posts as the <tt>target</tt>.
         
     | 
| 
       22 
19 
     | 
    
         
             
                #
         
     | 
| 
       23 
     | 
    
         
            -
                # This class delegates unknown methods to <tt 
     | 
| 
       24 
     | 
    
         
            -
                #  
     | 
| 
      
 20 
     | 
    
         
            +
                # This class delegates unknown methods to the <tt>association</tt>'s
         
     | 
| 
      
 21 
     | 
    
         
            +
                # relation class via a delegate cache.
         
     | 
| 
       25 
22 
     | 
    
         
             
                #
         
     | 
| 
       26 
     | 
    
         
            -
                # The <tt 
     | 
| 
      
 23 
     | 
    
         
            +
                # The <tt>target</tt> result set is not loaded until needed. For example,
         
     | 
| 
       27 
24 
     | 
    
         
             
                #
         
     | 
| 
       28 
25 
     | 
    
         
             
                #   blog.posts.count
         
     | 
| 
       29 
26 
     | 
    
         
             
                #
         
     | 
| 
       30 
27 
     | 
    
         
             
                # is computed directly through SQL and does not trigger by itself the
         
     | 
| 
       31 
28 
     | 
    
         
             
                # instantiation of the actual post records.
         
     | 
| 
       32 
29 
     | 
    
         
             
                class CollectionProxy < Relation
         
     | 
| 
       33 
     | 
    
         
            -
                  def initialize(klass, association)  
     | 
| 
      
 30 
     | 
    
         
            +
                  def initialize(klass, association, **) # :nodoc:
         
     | 
| 
       34 
31 
     | 
    
         
             
                    @association = association
         
     | 
| 
       35 
32 
     | 
    
         
             
                    super klass
         
     | 
| 
       36 
33 
     | 
    
         | 
| 
         @@ -49,11 +46,12 @@ module ActiveRecord 
     | 
|
| 
       49 
46 
     | 
    
         
             
                  # Returns +true+ if the association has been loaded, otherwise +false+.
         
     | 
| 
       50 
47 
     | 
    
         
             
                  #
         
     | 
| 
       51 
48 
     | 
    
         
             
                  #   person.pets.loaded? # => false
         
     | 
| 
       52 
     | 
    
         
            -
                  #   person.pets
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #   person.pets.records
         
     | 
| 
       53 
50 
     | 
    
         
             
                  #   person.pets.loaded? # => true
         
     | 
| 
       54 
51 
     | 
    
         
             
                  def loaded?
         
     | 
| 
       55 
52 
     | 
    
         
             
                    @association.loaded?
         
     | 
| 
       56 
53 
     | 
    
         
             
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  alias :loaded :loaded?
         
     | 
| 
       57 
55 
     | 
    
         | 
| 
       58 
56 
     | 
    
         
             
                  ##
         
     | 
| 
       59 
57 
     | 
    
         
             
                  # :method: select
         
     | 
| 
         @@ -103,7 +101,7 @@ module ActiveRecord 
     | 
|
| 
       103 
101 
     | 
    
         
             
                  # converting them into an array and iterating through them using
         
     | 
| 
       104 
102 
     | 
    
         
             
                  # Array#select.
         
     | 
| 
       105 
103 
     | 
    
         
             
                  #
         
     | 
| 
       106 
     | 
    
         
            -
                  #   person.pets.select { |pet| pet.name  
     | 
| 
      
 104 
     | 
    
         
            +
                  #   person.pets.select { |pet| /oo/.match?(pet.name) }
         
     | 
| 
       107 
105 
     | 
    
         
             
                  #   # => [
         
     | 
| 
       108 
106 
     | 
    
         
             
                  #   #      #<Pet id: 2, name: "Spook", person_id: 1>,
         
     | 
| 
       109 
107 
     | 
    
         
             
                  #   #      #<Pet id: 3, name: "Choo-Choo", person_id: 1>
         
     | 
| 
         @@ -376,7 +374,7 @@ module ActiveRecord 
     | 
|
| 
       376 
374 
     | 
    
         
             
                  #   person.pets
         
     | 
| 
       377 
375 
     | 
    
         
             
                  #   # => [#<Pet id: 1, name: "Gorby", group: "cats", person_id: 1>]
         
     | 
| 
       378 
376 
     | 
    
         
             
                  #
         
     | 
| 
       379 
     | 
    
         
            -
                  #   other_pets = [Pet.new(name: 'Puff', group: 'celebrities']
         
     | 
| 
      
 377 
     | 
    
         
            +
                  #   other_pets = [Pet.new(name: 'Puff', group: 'celebrities')]
         
     | 
| 
       380 
378 
     | 
    
         
             
                  #
         
     | 
| 
       381 
379 
     | 
    
         
             
                  #   person.pets.replace(other_pets)
         
     | 
| 
       382 
380 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -815,7 +813,7 @@ module ActiveRecord 
     | 
|
| 
       815 
813 
     | 
    
         
             
                  # to <tt>collection.size.zero?</tt>. If the collection has not been loaded,
         
     | 
| 
       816 
814 
     | 
    
         
             
                  # it is equivalent to <tt>!collection.exists?</tt>. If the collection has
         
     | 
| 
       817 
815 
     | 
    
         
             
                  # not already been loaded and you are going to fetch the records anyway it
         
     | 
| 
       818 
     | 
    
         
            -
                  # is better to check <tt>collection. 
     | 
| 
      
 816 
     | 
    
         
            +
                  # is better to check <tt>collection.load.empty?</tt>.
         
     | 
| 
       819 
817 
     | 
    
         
             
                  #
         
     | 
| 
       820 
818 
     | 
    
         
             
                  #   class Person < ActiveRecord::Base
         
     | 
| 
       821 
819 
     | 
    
         
             
                  #     has_many :pets
         
     | 
| 
         @@ -851,6 +849,11 @@ module ActiveRecord 
     | 
|
| 
       851 
849 
     | 
    
         
             
                  #   person.pets.count # => 1
         
     | 
| 
       852 
850 
     | 
    
         
             
                  #   person.pets.any?  # => true
         
     | 
| 
       853 
851 
     | 
    
         
             
                  #
         
     | 
| 
      
 852 
     | 
    
         
            +
                  # Calling it without a block when the collection is not yet
         
     | 
| 
      
 853 
     | 
    
         
            +
                  # loaded is equivalent to <tt>collection.exists?</tt>.
         
     | 
| 
      
 854 
     | 
    
         
            +
                  # If you're going to load the collection anyway, it is better
         
     | 
| 
      
 855 
     | 
    
         
            +
                  # to call <tt>collection.load.any?</tt> to avoid an extra query.
         
     | 
| 
      
 856 
     | 
    
         
            +
                  #
         
     | 
| 
       854 
857 
     | 
    
         
             
                  # You can also pass a +block+ to define criteria. The behavior
         
     | 
| 
       855 
858 
     | 
    
         
             
                  # is the same, it returns true if the collection based on the
         
     | 
| 
       856 
859 
     | 
    
         
             
                  # criteria is not empty.
         
     | 
| 
         @@ -923,7 +926,7 @@ module ActiveRecord 
     | 
|
| 
       923 
926 
     | 
    
         
             
                    !!@association.include?(record)
         
     | 
| 
       924 
927 
     | 
    
         
             
                  end
         
     | 
| 
       925 
928 
     | 
    
         | 
| 
       926 
     | 
    
         
            -
                  def proxy_association
         
     | 
| 
      
 929 
     | 
    
         
            +
                  def proxy_association # :nodoc:
         
     | 
| 
       927 
930 
     | 
    
         
             
                    @association
         
     | 
| 
       928 
931 
     | 
    
         
             
                  end
         
     | 
| 
       929 
932 
     | 
    
         | 
| 
         @@ -1005,7 +1008,7 @@ module ActiveRecord 
     | 
|
| 
       1005 
1008 
     | 
    
         
             
                  end
         
     | 
| 
       1006 
1009 
     | 
    
         | 
| 
       1007 
1010 
     | 
    
         
             
                  # Adds one or more +records+ to the collection by setting their foreign keys
         
     | 
| 
       1008 
     | 
    
         
            -
                  # to the association's primary key. Since  
     | 
| 
      
 1011 
     | 
    
         
            +
                  # to the association's primary key. Since <tt><<</tt> flattens its argument list and
         
     | 
| 
       1009 
1012 
     | 
    
         
             
                  # inserts each record, +push+ and +concat+ behave identically. Returns +self+
         
     | 
| 
       1010 
1013 
     | 
    
         
             
                  # so several appends may be chained together.
         
     | 
| 
       1011 
1014 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -1032,7 +1035,7 @@ module ActiveRecord 
     | 
|
| 
       1032 
1035 
     | 
    
         
             
                  alias_method :append, :<<
         
     | 
| 
       1033 
1036 
     | 
    
         
             
                  alias_method :concat, :<<
         
     | 
| 
       1034 
1037 
     | 
    
         | 
| 
       1035 
     | 
    
         
            -
                  def prepend(*args)
         
     | 
| 
      
 1038 
     | 
    
         
            +
                  def prepend(*args) # :nodoc:
         
     | 
| 
       1036 
1039 
     | 
    
         
             
                    raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
         
     | 
| 
       1037 
1040 
     | 
    
         
             
                  end
         
     | 
| 
       1038 
1041 
     | 
    
         | 
| 
         @@ -1062,7 +1065,7 @@ module ActiveRecord 
     | 
|
| 
       1062 
1065 
     | 
    
         
             
                  #   person.pets.reload # fetches pets from the database
         
     | 
| 
       1063 
1066 
     | 
    
         
             
                  #   # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
         
     | 
| 
       1064 
1067 
     | 
    
         
             
                  def reload
         
     | 
| 
       1065 
     | 
    
         
            -
                    proxy_association.reload
         
     | 
| 
      
 1068 
     | 
    
         
            +
                    proxy_association.reload(true)
         
     | 
| 
       1066 
1069 
     | 
    
         
             
                    reset_scope
         
     | 
| 
       1067 
1070 
     | 
    
         
             
                  end
         
     | 
| 
       1068 
1071 
     | 
    
         | 
| 
         @@ -1089,22 +1092,28 @@ module ActiveRecord 
     | 
|
| 
       1089 
1092 
     | 
    
         
             
                  end
         
     | 
| 
       1090 
1093 
     | 
    
         | 
| 
       1091 
1094 
     | 
    
         
             
                  def reset_scope # :nodoc:
         
     | 
| 
       1092 
     | 
    
         
            -
                    @offsets =  
     | 
| 
      
 1095 
     | 
    
         
            +
                    @offsets = @take = nil
         
     | 
| 
       1093 
1096 
     | 
    
         
             
                    @scope = nil
         
     | 
| 
       1094 
1097 
     | 
    
         
             
                    self
         
     | 
| 
       1095 
1098 
     | 
    
         
             
                  end
         
     | 
| 
       1096 
1099 
     | 
    
         | 
| 
      
 1100 
     | 
    
         
            +
                  def inspect # :nodoc:
         
     | 
| 
      
 1101 
     | 
    
         
            +
                    load_target if find_from_target?
         
     | 
| 
      
 1102 
     | 
    
         
            +
                    super
         
     | 
| 
      
 1103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1104 
     | 
    
         
            +
             
     | 
| 
       1097 
1105 
     | 
    
         
             
                  delegate_methods = [
         
     | 
| 
       1098 
1106 
     | 
    
         
             
                    QueryMethods,
         
     | 
| 
       1099 
1107 
     | 
    
         
             
                    SpawnMethods,
         
     | 
| 
       1100 
1108 
     | 
    
         
             
                  ].flat_map { |klass|
         
     | 
| 
       1101 
1109 
     | 
    
         
             
                    klass.public_instance_methods(false)
         
     | 
| 
       1102 
     | 
    
         
            -
                  } - self.public_instance_methods(false) - [:select] + [ 
     | 
| 
      
 1110 
     | 
    
         
            +
                  } - self.public_instance_methods(false) - [:select] + [
         
     | 
| 
      
 1111 
     | 
    
         
            +
                    :scoping, :values, :insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all
         
     | 
| 
      
 1112 
     | 
    
         
            +
                  ]
         
     | 
| 
       1103 
1113 
     | 
    
         | 
| 
       1104 
1114 
     | 
    
         
             
                  delegate(*delegate_methods, to: :scope)
         
     | 
| 
       1105 
1115 
     | 
    
         | 
| 
       1106 
1116 
     | 
    
         
             
                  private
         
     | 
| 
       1107 
     | 
    
         
            -
             
     | 
| 
       1108 
1117 
     | 
    
         
             
                    def find_nth_with_limit(index, limit)
         
     | 
| 
       1109 
1118 
     | 
    
         
             
                      load_target if find_from_target?
         
     | 
| 
       1110 
1119 
     | 
    
         
             
                      super
         
     | 
| 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActiveRecord
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Associations
         
     | 
| 
      
 5 
     | 
    
         
            +
                class DisableJoinsAssociationScope < AssociationScope # :nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def scope(association)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    source_reflection = association.reflection
         
     | 
| 
      
 8 
     | 
    
         
            +
                    owner = association.owner
         
     | 
| 
      
 9 
     | 
    
         
            +
                    unscoped = association.klass.unscoped
         
     | 
| 
      
 10 
     | 
    
         
            +
                    reverse_chain = get_chain(source_reflection, association, unscoped.alias_tracker).reverse
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    last_reflection, last_ordered, last_join_ids = last_scope_chain(reverse_chain, owner)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    add_constraints(last_reflection, last_reflection.join_primary_key, last_join_ids, owner, last_ordered)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  private
         
     | 
| 
      
 18 
     | 
    
         
            +
                    def last_scope_chain(reverse_chain, owner)
         
     | 
| 
      
 19 
     | 
    
         
            +
                      first_item = reverse_chain.shift
         
     | 
| 
      
 20 
     | 
    
         
            +
                      first_scope = [first_item, false, [owner._read_attribute(first_item.join_foreign_key)]]
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                      reverse_chain.inject(first_scope) do |(reflection, ordered, join_ids), next_reflection|
         
     | 
| 
      
 23 
     | 
    
         
            +
                        key = reflection.join_primary_key
         
     | 
| 
      
 24 
     | 
    
         
            +
                        records = add_constraints(reflection, key, join_ids, owner, ordered)
         
     | 
| 
      
 25 
     | 
    
         
            +
                        foreign_key = next_reflection.join_foreign_key
         
     | 
| 
      
 26 
     | 
    
         
            +
                        record_ids = records.pluck(foreign_key)
         
     | 
| 
      
 27 
     | 
    
         
            +
                        records_ordered = records && records.order_values.any?
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                        [next_reflection, records_ordered, record_ids]
         
     | 
| 
      
 30 
     | 
    
         
            +
                      end
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    def add_constraints(reflection, key, join_ids, owner, ordered)
         
     | 
| 
      
 34 
     | 
    
         
            +
                      scope = reflection.build_scope(reflection.aliased_table).where(key => join_ids)
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                      relation = reflection.klass.scope_for_association
         
     | 
| 
      
 37 
     | 
    
         
            +
                      scope.merge!(
         
     | 
| 
      
 38 
     | 
    
         
            +
                        relation.except(:select, :create_with, :includes, :preload, :eager_load, :joins, :left_outer_joins)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      )
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                      scope = reflection.constraints.inject(scope) do |memo, scope_chain_item|
         
     | 
| 
      
 42 
     | 
    
         
            +
                        item = eval_scope(reflection, scope_chain_item, owner)
         
     | 
| 
      
 43 
     | 
    
         
            +
                        scope.unscope!(*item.unscope_values)
         
     | 
| 
      
 44 
     | 
    
         
            +
                        scope.where_clause += item.where_clause
         
     | 
| 
      
 45 
     | 
    
         
            +
                        scope.order_values = item.order_values | scope.order_values
         
     | 
| 
      
 46 
     | 
    
         
            +
                        scope
         
     | 
| 
      
 47 
     | 
    
         
            +
                      end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                      if scope.order_values.empty? && ordered
         
     | 
| 
      
 50 
     | 
    
         
            +
                        split_scope = DisableJoinsAssociationRelation.create(scope.klass, key, join_ids)
         
     | 
| 
      
 51 
     | 
    
         
            +
                        split_scope.where_clause += scope.where_clause
         
     | 
| 
      
 52 
     | 
    
         
            +
                        split_scope
         
     | 
| 
      
 53 
     | 
    
         
            +
                      else
         
     | 
| 
      
 54 
     | 
    
         
            +
                        scope
         
     | 
| 
      
 55 
     | 
    
         
            +
                      end
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
            end
         
     |