ibm_db 5.6.1-arm64-darwin-24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES +299 -0
- data/LICENSE +55 -0
- data/MANIFEST +14 -0
- data/ParameterizedQueries README +39 -0
- data/README +210 -0
- data/ext/Makefile +270 -0
- data/ext/Makefile.nt32 +181 -0
- data/ext/Makefile.nt32.191 +212 -0
- data/ext/extconf.rb +320 -0
- data/ext/gil_release_version.h +3 -0
- data/ext/ibm_db.bundle +0 -0
- data/ext/ibm_db.c +11865 -0
- data/ext/ibm_db.o +0 -0
- data/ext/mkmf.log +98 -0
- data/ext/ruby_ibm_db.h +241 -0
- data/ext/ruby_ibm_db_cli.c +867 -0
- data/ext/ruby_ibm_db_cli.h +508 -0
- data/ext/ruby_ibm_db_cli.o +0 -0
- data/ext/unicode_support_version.h +3 -0
- data/init.rb +42 -0
- data/lib/IBM_DB.rb +27 -0
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +4407 -0
- data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
- data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -0
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
- data/lib/ibm_db.bundle +0 -0
- data/test/active_record/connection_adapters/fake_adapter.rb +52 -0
- data/test/activejob/destroy_association_async_test.rb +305 -0
- data/test/activejob/destroy_async_job_not_present_test.rb +31 -0
- data/test/activejob/helper.rb +15 -0
- data/test/assets/example.log +1 -0
- data/test/assets/flowers.jpg +0 -0
- data/test/assets/schema_dump_5_1.yml +345 -0
- data/test/assets/test.txt +1 -0
- data/test/cases/adapter_prevent_writes_test.rb +334 -0
- data/test/cases/adapter_test.rb +565 -0
- data/test/cases/adapters/mysql2/active_schema_test.rb +203 -0
- data/test/cases/adapters/mysql2/auto_increment_test.rb +34 -0
- data/test/cases/adapters/mysql2/bind_parameter_test.rb +52 -0
- data/test/cases/adapters/mysql2/boolean_test.rb +102 -0
- data/test/cases/adapters/mysql2/case_sensitivity_test.rb +65 -0
- data/test/cases/adapters/mysql2/charset_collation_test.rb +57 -0
- data/test/cases/adapters/mysql2/connection_test.rb +208 -0
- data/test/cases/adapters/mysql2/count_deleted_rows_with_lock_test.rb +28 -0
- data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +49 -0
- data/test/cases/adapters/mysql2/enum_test.rb +47 -0
- data/test/cases/adapters/mysql2/explain_test.rb +23 -0
- data/test/cases/adapters/mysql2/json_test.rb +24 -0
- data/test/cases/adapters/mysql2/mysql2_adapter_prevent_writes_test.rb +208 -0
- data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +238 -0
- data/test/cases/adapters/mysql2/nested_deadlock_test.rb +75 -0
- data/test/cases/adapters/mysql2/optimizer_hints_test.rb +69 -0
- data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
- data/test/cases/adapters/mysql2/schema_migrations_test.rb +64 -0
- data/test/cases/adapters/mysql2/schema_test.rb +128 -0
- data/test/cases/adapters/mysql2/set_test.rb +32 -0
- data/test/cases/adapters/mysql2/sp_test.rb +38 -0
- data/test/cases/adapters/mysql2/sql_types_test.rb +16 -0
- data/test/cases/adapters/mysql2/table_options_test.rb +125 -0
- data/test/cases/adapters/mysql2/transaction_test.rb +151 -0
- data/test/cases/adapters/mysql2/unsigned_type_test.rb +68 -0
- data/test/cases/adapters/mysql2/virtual_column_test.rb +66 -0
- data/test/cases/adapters/postgresql/active_schema_test.rb +113 -0
- data/test/cases/adapters/postgresql/array_test.rb +394 -0
- data/test/cases/adapters/postgresql/bit_string_test.rb +84 -0
- data/test/cases/adapters/postgresql/bytea_test.rb +135 -0
- data/test/cases/adapters/postgresql/case_insensitive_test.rb +27 -0
- data/test/cases/adapters/postgresql/change_schema_test.rb +40 -0
- data/test/cases/adapters/postgresql/cidr_test.rb +27 -0
- data/test/cases/adapters/postgresql/citext_test.rb +78 -0
- data/test/cases/adapters/postgresql/collation_test.rb +55 -0
- data/test/cases/adapters/postgresql/composite_test.rb +134 -0
- data/test/cases/adapters/postgresql/connection_test.rb +245 -0
- data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +74 -0
- data/test/cases/adapters/postgresql/datatype_test.rb +89 -0
- data/test/cases/adapters/postgresql/date_test.rb +42 -0
- data/test/cases/adapters/postgresql/domain_test.rb +49 -0
- data/test/cases/adapters/postgresql/enum_test.rb +93 -0
- data/test/cases/adapters/postgresql/explain_test.rb +22 -0
- data/test/cases/adapters/postgresql/extension_migration_test.rb +64 -0
- data/test/cases/adapters/postgresql/foreign_table_test.rb +109 -0
- data/test/cases/adapters/postgresql/full_text_test.rb +46 -0
- data/test/cases/adapters/postgresql/geometric_test.rb +372 -0
- data/test/cases/adapters/postgresql/hstore_test.rb +390 -0
- data/test/cases/adapters/postgresql/infinity_test.rb +108 -0
- data/test/cases/adapters/postgresql/integer_test.rb +27 -0
- data/test/cases/adapters/postgresql/interval_test.rb +99 -0
- data/test/cases/adapters/postgresql/json_test.rb +52 -0
- data/test/cases/adapters/postgresql/ltree_test.rb +51 -0
- data/test/cases/adapters/postgresql/money_test.rb +127 -0
- data/test/cases/adapters/postgresql/network_test.rb +102 -0
- data/test/cases/adapters/postgresql/numbers_test.rb +51 -0
- data/test/cases/adapters/postgresql/optimizer_hints_test.rb +71 -0
- data/test/cases/adapters/postgresql/partitions_test.rb +22 -0
- data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +205 -0
- data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +447 -0
- data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +27 -0
- data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
- data/test/cases/adapters/postgresql/quoting_test.rb +50 -0
- data/test/cases/adapters/postgresql/range_test.rb +457 -0
- data/test/cases/adapters/postgresql/referential_integrity_test.rb +112 -0
- data/test/cases/adapters/postgresql/rename_table_test.rb +35 -0
- data/test/cases/adapters/postgresql/schema_authorization_test.rb +110 -0
- data/test/cases/adapters/postgresql/schema_test.rb +713 -0
- data/test/cases/adapters/postgresql/serial_test.rb +156 -0
- data/test/cases/adapters/postgresql/statement_pool_test.rb +61 -0
- data/test/cases/adapters/postgresql/timestamp_test.rb +92 -0
- data/test/cases/adapters/postgresql/transaction_nested_test.rb +114 -0
- data/test/cases/adapters/postgresql/transaction_test.rb +189 -0
- data/test/cases/adapters/postgresql/type_lookup_test.rb +35 -0
- data/test/cases/adapters/postgresql/utils_test.rb +64 -0
- data/test/cases/adapters/postgresql/uuid_test.rb +411 -0
- data/test/cases/adapters/postgresql/xml_test.rb +50 -0
- data/test/cases/adapters/sqlite3/collation_test.rb +64 -0
- data/test/cases/adapters/sqlite3/copy_table_test.rb +101 -0
- data/test/cases/adapters/sqlite3/explain_test.rb +23 -0
- data/test/cases/adapters/sqlite3/json_test.rb +29 -0
- data/test/cases/adapters/sqlite3/quoting_test.rb +79 -0
- data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +186 -0
- data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +628 -0
- data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
- data/test/cases/adapters/sqlite3/statement_pool_test.rb +21 -0
- data/test/cases/adapters/sqlite3/transaction_test.rb +123 -0
- data/test/cases/aggregations_test.rb +170 -0
- data/test/cases/annotate_test.rb +46 -0
- data/test/cases/ar_schema_test.rb +213 -0
- data/test/cases/arel/attributes/attribute_test.rb +1145 -0
- data/test/cases/arel/attributes/math_test.rb +83 -0
- data/test/cases/arel/attributes_test.rb +27 -0
- data/test/cases/arel/collectors/bind_test.rb +40 -0
- data/test/cases/arel/collectors/composite_test.rb +47 -0
- data/test/cases/arel/collectors/sql_string_test.rb +41 -0
- data/test/cases/arel/collectors/substitute_bind_collector_test.rb +48 -0
- data/test/cases/arel/crud_test.rb +65 -0
- data/test/cases/arel/delete_manager_test.rb +53 -0
- data/test/cases/arel/factory_methods_test.rb +46 -0
- data/test/cases/arel/helper.rb +45 -0
- data/test/cases/arel/insert_manager_test.rb +241 -0
- data/test/cases/arel/nodes/and_test.rb +30 -0
- data/test/cases/arel/nodes/as_test.rb +36 -0
- data/test/cases/arel/nodes/ascending_test.rb +46 -0
- data/test/cases/arel/nodes/bin_test.rb +35 -0
- data/test/cases/arel/nodes/binary_test.rb +29 -0
- data/test/cases/arel/nodes/bind_param_test.rb +22 -0
- data/test/cases/arel/nodes/case_test.rb +96 -0
- data/test/cases/arel/nodes/casted_test.rb +18 -0
- data/test/cases/arel/nodes/comment_test.rb +22 -0
- data/test/cases/arel/nodes/count_test.rb +35 -0
- data/test/cases/arel/nodes/delete_statement_test.rb +36 -0
- data/test/cases/arel/nodes/descending_test.rb +46 -0
- data/test/cases/arel/nodes/distinct_test.rb +21 -0
- data/test/cases/arel/nodes/equality_test.rb +62 -0
- data/test/cases/arel/nodes/extract_test.rb +43 -0
- data/test/cases/arel/nodes/false_test.rb +21 -0
- data/test/cases/arel/nodes/grouping_test.rb +26 -0
- data/test/cases/arel/nodes/infix_operation_test.rb +42 -0
- data/test/cases/arel/nodes/insert_statement_test.rb +44 -0
- data/test/cases/arel/nodes/named_function_test.rb +48 -0
- data/test/cases/arel/nodes/node_test.rb +22 -0
- data/test/cases/arel/nodes/not_test.rb +31 -0
- data/test/cases/arel/nodes/or_test.rb +36 -0
- data/test/cases/arel/nodes/over_test.rb +69 -0
- data/test/cases/arel/nodes/select_core_test.rb +79 -0
- data/test/cases/arel/nodes/select_statement_test.rb +51 -0
- data/test/cases/arel/nodes/sql_literal_test.rb +75 -0
- data/test/cases/arel/nodes/sum_test.rb +35 -0
- data/test/cases/arel/nodes/table_alias_test.rb +29 -0
- data/test/cases/arel/nodes/true_test.rb +21 -0
- data/test/cases/arel/nodes/unary_operation_test.rb +41 -0
- data/test/cases/arel/nodes/update_statement_test.rb +60 -0
- data/test/cases/arel/nodes/window_test.rb +81 -0
- data/test/cases/arel/nodes_test.rb +34 -0
- data/test/cases/arel/select_manager_test.rb +1238 -0
- data/test/cases/arel/support/fake_record.rb +135 -0
- data/test/cases/arel/table_test.rb +216 -0
- data/test/cases/arel/update_manager_test.rb +126 -0
- data/test/cases/arel/visitors/dispatch_contamination_test.rb +78 -0
- data/test/cases/arel/visitors/dot_test.rb +90 -0
- data/test/cases/arel/visitors/mysql_test.rb +157 -0
- data/test/cases/arel/visitors/postgres_test.rb +366 -0
- data/test/cases/arel/visitors/sqlite_test.rb +75 -0
- data/test/cases/arel/visitors/to_sql_test.rb +750 -0
- data/test/cases/associations/association_scope_test.rb +16 -0
- data/test/cases/associations/belongs_to_associations_test.rb +1493 -0
- data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +43 -0
- data/test/cases/associations/callbacks_test.rb +208 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +245 -0
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +156 -0
- data/test/cases/associations/eager_load_nested_include_test.rb +127 -0
- data/test/cases/associations/eager_singularization_test.rb +148 -0
- data/test/cases/associations/eager_test.rb +1658 -0
- data/test/cases/associations/extension_test.rb +93 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1025 -0
- data/test/cases/associations/has_many_associations_test.rb +3074 -0
- data/test/cases/associations/has_many_through_associations_test.rb +1580 -0
- data/test/cases/associations/has_one_associations_test.rb +872 -0
- data/test/cases/associations/has_one_through_associations_test.rb +429 -0
- data/test/cases/associations/inner_join_association_test.rb +215 -0
- data/test/cases/associations/inverse_associations_test.rb +941 -0
- data/test/cases/associations/join_model_test.rb +787 -0
- data/test/cases/associations/left_outer_join_association_test.rb +123 -0
- data/test/cases/associations/nested_through_associations_test.rb +636 -0
- data/test/cases/associations/required_test.rb +127 -0
- data/test/cases/associations_test.rb +516 -0
- data/test/cases/attribute_decorators_test.rb +126 -0
- data/test/cases/attribute_methods/read_test.rb +60 -0
- data/test/cases/attribute_methods_test.rb +1124 -0
- data/test/cases/attribute_set_test.rb +270 -0
- data/test/cases/attribute_test.rb +246 -0
- data/test/cases/attributes_test.rb +371 -0
- data/test/cases/autosave_association_test.rb +1953 -0
- data/test/cases/base_prevent_writes_test.rb +229 -0
- data/test/cases/base_test.rb +1770 -0
- data/test/cases/batches_test.rb +695 -0
- data/test/cases/binary_test.rb +39 -0
- data/test/cases/bind_parameter_test.rb +283 -0
- data/test/cases/boolean_test.rb +52 -0
- data/test/cases/cache_key_test.rb +131 -0
- data/test/cases/calculations_test.rb +1361 -0
- data/test/cases/callbacks_test.rb +503 -0
- data/test/cases/clone_test.rb +45 -0
- data/test/cases/coders/json_test.rb +17 -0
- data/test/cases/coders/yaml_column_test.rb +66 -0
- data/test/cases/collection_cache_key_test.rb +272 -0
- data/test/cases/column_alias_test.rb +19 -0
- data/test/cases/column_definition_test.rb +34 -0
- data/test/cases/comment_test.rb +204 -0
- data/test/cases/connection_adapters/adapter_leasing_test.rb +60 -0
- data/test/cases/connection_adapters/connection_handler_test.rb +467 -0
- data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +400 -0
- data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +103 -0
- data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +499 -0
- data/test/cases/connection_adapters/connection_specification_test.rb +12 -0
- data/test/cases/connection_adapters/connection_swapping_nested_test.rb +457 -0
- data/test/cases/connection_adapters/legacy_connection_handlers_multi_db_test.rb +486 -0
- data/test/cases/connection_adapters/legacy_connection_handlers_sharding_db_test.rb +586 -0
- data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +436 -0
- data/test/cases/connection_adapters/mysql_type_lookup_test.rb +81 -0
- data/test/cases/connection_adapters/quoting_test.rb +13 -0
- data/test/cases/connection_adapters/schema_cache_test.rb +294 -0
- data/test/cases/connection_adapters/type_lookup_test.rb +119 -0
- data/test/cases/connection_management_test.rb +114 -0
- data/test/cases/connection_pool_test.rb +754 -0
- data/test/cases/connection_specification/resolver_test.rb +131 -0
- data/test/cases/core_test.rb +136 -0
- data/test/cases/counter_cache_test.rb +368 -0
- data/test/cases/custom_locking_test.rb +19 -0
- data/test/cases/database_configurations/hash_config_test.rb +74 -0
- data/test/cases/database_configurations/resolver_test.rb +150 -0
- data/test/cases/database_configurations_test.rb +145 -0
- data/test/cases/database_selector_test.rb +296 -0
- data/test/cases/database_statements_test.rb +36 -0
- data/test/cases/date_test.rb +36 -0
- data/test/cases/date_time_precision_test.rb +129 -0
- data/test/cases/date_time_test.rb +76 -0
- data/test/cases/defaults_test.rb +254 -0
- data/test/cases/delegated_type_test.rb +57 -0
- data/test/cases/dirty_test.rb +959 -0
- data/test/cases/disconnected_test.rb +30 -0
- data/test/cases/dup_test.rb +184 -0
- data/test/cases/enum_test.rb +823 -0
- data/test/cases/errors_test.rb +16 -0
- data/test/cases/explain_subscriber_test.rb +66 -0
- data/test/cases/explain_test.rb +79 -0
- data/test/cases/filter_attributes_test.rb +153 -0
- data/test/cases/finder_respond_to_test.rb +60 -0
- data/test/cases/finder_test.rb +1676 -0
- data/test/cases/fixture_set/file_test.rb +152 -0
- data/test/cases/fixtures_test.rb +1645 -0
- data/test/cases/forbidden_attributes_protection_test.rb +130 -0
- data/test/cases/habtm_destroy_order_test.rb +61 -0
- data/test/cases/helper.rb +233 -0
- data/test/cases/hot_compatibility_test.rb +143 -0
- data/test/cases/i18n_test.rb +46 -0
- data/test/cases/inheritance_test.rb +671 -0
- data/test/cases/insert_all_test.rb +489 -0
- data/test/cases/instrumentation_test.rb +101 -0
- data/test/cases/integration_test.rb +243 -0
- data/test/cases/invalid_connection_test.rb +26 -0
- data/test/cases/invertible_migration_test.rb +527 -0
- data/test/cases/json_attribute_test.rb +35 -0
- data/test/cases/json_serialization_test.rb +310 -0
- data/test/cases/json_shared_test_cases.rb +290 -0
- data/test/cases/locking_test.rb +787 -0
- data/test/cases/log_subscriber_test.rb +267 -0
- data/test/cases/marshal_serialization_test.rb +39 -0
- data/test/cases/migration/change_schema_test.rb +504 -0
- data/test/cases/migration/change_table_test.rb +364 -0
- data/test/cases/migration/check_constraint_test.rb +162 -0
- data/test/cases/migration/column_attributes_test.rb +186 -0
- data/test/cases/migration/column_positioning_test.rb +68 -0
- data/test/cases/migration/columns_test.rb +326 -0
- data/test/cases/migration/command_recorder_test.rb +437 -0
- data/test/cases/migration/compatibility_test.rb +673 -0
- data/test/cases/migration/create_join_table_test.rb +167 -0
- data/test/cases/migration/foreign_key_test.rb +581 -0
- data/test/cases/migration/helper.rb +40 -0
- data/test/cases/migration/index_test.rb +267 -0
- data/test/cases/migration/logger_test.rb +39 -0
- data/test/cases/migration/pending_migrations_test.rb +106 -0
- data/test/cases/migration/references_foreign_key_test.rb +235 -0
- data/test/cases/migration/references_index_test.rb +120 -0
- data/test/cases/migration/references_statements_test.rb +137 -0
- data/test/cases/migration/rename_table_test.rb +116 -0
- data/test/cases/migration_test.rb +1525 -0
- data/test/cases/migrator_test.rb +527 -0
- data/test/cases/mixin_test.rb +64 -0
- data/test/cases/modules_test.rb +174 -0
- data/test/cases/multi_db_migrator_test.rb +223 -0
- data/test/cases/multiparameter_attributes_test.rb +399 -0
- data/test/cases/multiple_db_test.rb +116 -0
- data/test/cases/nested_attributes_test.rb +1119 -0
- data/test/cases/nested_attributes_with_callbacks_test.rb +146 -0
- data/test/cases/null_relation_test.rb +84 -0
- data/test/cases/numeric_data_test.rb +93 -0
- data/test/cases/persistence_test.rb +1093 -0
- data/test/cases/pooled_connections_test.rb +73 -0
- data/test/cases/prepared_statement_status_test.rb +48 -0
- data/test/cases/primary_keys_test.rb +482 -0
- data/test/cases/query_cache_test.rb +915 -0
- data/test/cases/quoting_test.rb +303 -0
- data/test/cases/readonly_test.rb +120 -0
- data/test/cases/reaper_test.rb +199 -0
- data/test/cases/reflection_test.rb +520 -0
- data/test/cases/relation/delegation_test.rb +76 -0
- data/test/cases/relation/delete_all_test.rb +117 -0
- data/test/cases/relation/merging_test.rb +434 -0
- data/test/cases/relation/mutation_test.rb +145 -0
- data/test/cases/relation/or_test.rb +192 -0
- data/test/cases/relation/predicate_builder_test.rb +31 -0
- data/test/cases/relation/record_fetch_warning_test.rb +42 -0
- data/test/cases/relation/select_test.rb +67 -0
- data/test/cases/relation/update_all_test.rb +317 -0
- data/test/cases/relation/where_chain_test.rb +141 -0
- data/test/cases/relation/where_clause_test.rb +257 -0
- data/test/cases/relation/where_test.rb +429 -0
- data/test/cases/relation_test.rb +482 -0
- data/test/cases/relations_test.rb +2251 -0
- data/test/cases/reload_models_test.rb +26 -0
- data/test/cases/reserved_word_test.rb +141 -0
- data/test/cases/result_test.rb +141 -0
- data/test/cases/sanitize_test.rb +192 -0
- data/test/cases/schema_dumper_test.rb +550 -0
- data/test/cases/schema_loading_test.rb +53 -0
- data/test/cases/scoping/default_scoping_test.rb +569 -0
- data/test/cases/scoping/named_scoping_test.rb +649 -0
- data/test/cases/scoping/relation_scoping_test.rb +522 -0
- data/test/cases/secure_token_test.rb +47 -0
- data/test/cases/serialization_test.rb +106 -0
- data/test/cases/serialized_attribute_test.rb +455 -0
- data/test/cases/signed_id_test.rb +168 -0
- data/test/cases/statement_cache_test.rb +153 -0
- data/test/cases/statement_invalid_test.rb +42 -0
- data/test/cases/store_test.rb +320 -0
- data/test/cases/strict_loading_test.rb +473 -0
- data/test/cases/suppressor_test.rb +77 -0
- data/test/cases/tasks/database_tasks_test.rb +1526 -0
- data/test/cases/tasks/mysql_rake_test.rb +417 -0
- data/test/cases/tasks/postgresql_rake_test.rb +534 -0
- data/test/cases/tasks/sqlite_rake_test.rb +267 -0
- data/test/cases/test_case.rb +142 -0
- data/test/cases/test_databases_test.rb +79 -0
- data/test/cases/test_fixtures_test.rb +96 -0
- data/test/cases/time_precision_test.rb +125 -0
- data/test/cases/timestamp_test.rb +504 -0
- data/test/cases/touch_later_test.rb +123 -0
- data/test/cases/transaction_callbacks_test.rb +772 -0
- data/test/cases/transaction_isolation_test.rb +106 -0
- data/test/cases/transactions_test.rb +1285 -0
- data/test/cases/type/adapter_specific_registry_test.rb +145 -0
- data/test/cases/type/date_time_test.rb +16 -0
- data/test/cases/type/integer_test.rb +29 -0
- data/test/cases/type/string_test.rb +24 -0
- data/test/cases/type/time_test.rb +28 -0
- data/test/cases/type/type_map_test.rb +178 -0
- data/test/cases/type/unsigned_integer_test.rb +19 -0
- data/test/cases/type_test.rb +41 -0
- data/test/cases/types_test.rb +26 -0
- data/test/cases/unconnected_test.rb +46 -0
- data/test/cases/unsafe_raw_sql_test.rb +274 -0
- data/test/cases/validations/absence_validation_test.rb +75 -0
- data/test/cases/validations/association_validation_test.rb +99 -0
- data/test/cases/validations/i18n_generate_message_validation_test.rb +102 -0
- data/test/cases/validations/i18n_validation_test.rb +87 -0
- data/test/cases/validations/length_validation_test.rb +80 -0
- data/test/cases/validations/numericality_validation_test.rb +181 -0
- data/test/cases/validations/presence_validation_test.rb +105 -0
- data/test/cases/validations/uniqueness_validation_test.rb +618 -0
- data/test/cases/validations_repair_helper.rb +21 -0
- data/test/cases/validations_test.rb +229 -0
- data/test/cases/view_test.rb +222 -0
- data/test/cases/yaml_serialization_test.rb +166 -0
- data/test/config.example.yml +97 -0
- data/test/config.rb +7 -0
- data/test/config.yml +220 -0
- data/test/connections/native_ibm_db/connection.rb +44 -0
- data/test/fixtures/accounts.yml +29 -0
- data/test/fixtures/admin/accounts.yml +2 -0
- data/test/fixtures/admin/randomly_named_a9.yml +7 -0
- data/test/fixtures/admin/randomly_named_b0.yml +7 -0
- data/test/fixtures/admin/users.yml +10 -0
- data/test/fixtures/all/admin +1 -0
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/namespaced/accounts.yml +2 -0
- data/test/fixtures/all/people.yml +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author_addresses.yml +11 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +17 -0
- data/test/fixtures/bad_posts.yml +9 -0
- data/test/fixtures/binaries.yml +137 -0
- data/test/fixtures/books.yml +38 -0
- data/test/fixtures/bulbs.yml +5 -0
- data/test/fixtures/cars.yml +9 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories.yml +19 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +34 -0
- data/test/fixtures/categorizations.yml +23 -0
- data/test/fixtures/citations.yml +5 -0
- data/test/fixtures/clubs.yml +8 -0
- data/test/fixtures/collections.yml +3 -0
- data/test/fixtures/colleges.yml +3 -0
- data/test/fixtures/comments.yml +72 -0
- data/test/fixtures/companies.yml +72 -0
- data/test/fixtures/computers.yml +12 -0
- data/test/fixtures/content.yml +3 -0
- data/test/fixtures/content_positions.yml +3 -0
- data/test/fixtures/courses.yml +8 -0
- data/test/fixtures/customers.yml +35 -0
- data/test/fixtures/dashboards.yml +6 -0
- data/test/fixtures/dead_parrots.yml +5 -0
- data/test/fixtures/developers.yml +22 -0
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/dog_lovers.yml +7 -0
- data/test/fixtures/dogs.yml +4 -0
- data/test/fixtures/doubloons.yml +3 -0
- data/test/fixtures/edges.yml +5 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/essays.yml +16 -0
- data/test/fixtures/faces.yml +11 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/friendships.yml +4 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/humans.yml +5 -0
- data/test/fixtures/interests.yml +33 -0
- data/test/fixtures/items.yml +3 -0
- data/test/fixtures/jobs.yml +7 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/live_parrots.yml +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/member_details.yml +8 -0
- data/test/fixtures/member_types.yml +6 -0
- data/test/fixtures/members.yml +11 -0
- data/test/fixtures/memberships.yml +41 -0
- data/test/fixtures/men.yml +5 -0
- data/test/fixtures/minimalistics.yml +5 -0
- data/test/fixtures/minivans.yml +5 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixins.yml +29 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/naked/yml/courses_with_invalid_key.yml +3 -0
- data/test/fixtures/naked/yml/parrots.yml +3 -0
- data/test/fixtures/naked/yml/trees.yml +3 -0
- data/test/fixtures/nodes.yml +29 -0
- data/test/fixtures/organizations.yml +5 -0
- data/test/fixtures/other_books.yml +26 -0
- data/test/fixtures/other_comments.yml +6 -0
- data/test/fixtures/other_dogs.yml +2 -0
- data/test/fixtures/other_posts.yml +8 -0
- data/test/fixtures/other_topics.yml +42 -0
- data/test/fixtures/owners.yml +9 -0
- data/test/fixtures/parrots.yml +33 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/people.yml +24 -0
- data/test/fixtures/peoples_treasures.yml +3 -0
- data/test/fixtures/pets.yml +19 -0
- data/test/fixtures/pirates.yml +15 -0
- data/test/fixtures/posts.yml +88 -0
- data/test/fixtures/price_estimates.yml +16 -0
- data/test/fixtures/products.yml +4 -0
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/randomly_named_a9.yml +7 -0
- data/test/fixtures/ratings.yml +14 -0
- data/test/fixtures/readers.yml +17 -0
- data/test/fixtures/references.yml +17 -0
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distinct_select.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ships.yml +6 -0
- data/test/fixtures/speedometers.yml +8 -0
- data/test/fixtures/sponsors.yml +15 -0
- data/test/fixtures/strict_zines.yml +2 -0
- data/test/fixtures/string_key_objects.yml +7 -0
- data/test/fixtures/subscribers.yml +11 -0
- data/test/fixtures/subscriptions.yml +12 -0
- data/test/fixtures/taggings.yml +78 -0
- data/test/fixtures/tags.yml +11 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/teapots.yml +3 -0
- data/test/fixtures/to_be_linked/accounts.yml +2 -0
- data/test/fixtures/to_be_linked/users.yml +10 -0
- data/test/fixtures/topics.yml +49 -0
- data/test/fixtures/toys.yml +14 -0
- data/test/fixtures/traffic_lights.yml +10 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures/trees.yml +3 -0
- data/test/fixtures/uuid_children.yml +3 -0
- data/test/fixtures/uuid_parents.yml +2 -0
- data/test/fixtures/variants.yml +4 -0
- data/test/fixtures/vegetables.yml +20 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures/warehouse-things.yml +3 -0
- data/test/fixtures/warehouse_things.yml +3 -0
- data/test/fixtures/zines.yml +5 -0
- data/test/ibm_db_test.rb +25 -0
- data/test/migrations/10_urban/9_add_expressions.rb +13 -0
- data/test/migrations/decimal/1_give_me_big_numbers.rb +17 -0
- data/test/migrations/magic/1_currencies_have_symbols.rb +13 -0
- data/test/migrations/missing/1000_people_have_middle_names.rb +11 -0
- data/test/migrations/missing/1_people_have_last_names.rb +11 -0
- data/test/migrations/missing/3_we_need_reminders.rb +14 -0
- data/test/migrations/missing/4_innocent_jointable.rb +14 -0
- data/test/migrations/rename/1_we_need_things.rb +13 -0
- data/test/migrations/rename/2_rename_things.rb +11 -0
- data/test/migrations/to_copy/1_people_have_hobbies.rb +11 -0
- data/test/migrations/to_copy/2_people_have_descriptions.rb +11 -0
- data/test/migrations/to_copy2/1_create_articles.rb +9 -0
- data/test/migrations/to_copy2/2_create_comments.rb +9 -0
- data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +11 -0
- data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +11 -0
- data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +11 -0
- data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +9 -0
- data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +9 -0
- data/test/migrations/valid/1_valid_people_have_last_names.rb +11 -0
- data/test/migrations/valid/2_we_need_reminders.rb +14 -0
- data/test/migrations/valid/3_innocent_jointable.rb +14 -0
- data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +11 -0
- data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +14 -0
- data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +14 -0
- data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +11 -0
- data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +14 -0
- data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +14 -0
- data/test/migrations/version_check/20131219224947_migration_version_check.rb +10 -0
- data/test/models/account.rb +46 -0
- data/test/models/admin/account.rb +5 -0
- data/test/models/admin/randomly_named_c1.rb +9 -0
- data/test/models/admin/user.rb +48 -0
- data/test/models/admin.rb +7 -0
- data/test/models/aircraft.rb +7 -0
- data/test/models/arunit2_model.rb +5 -0
- data/test/models/author.rb +260 -0
- data/test/models/auto_id.rb +6 -0
- data/test/models/autoloadable/extra_firm.rb +4 -0
- data/test/models/binary.rb +4 -0
- data/test/models/binary_field.rb +6 -0
- data/test/models/bird.rb +24 -0
- data/test/models/book.rb +33 -0
- data/test/models/book_destroy_async.rb +24 -0
- data/test/models/boolean.rb +7 -0
- data/test/models/bulb.rb +61 -0
- data/test/models/cake_designer.rb +5 -0
- data/test/models/car.rb +36 -0
- data/test/models/carrier.rb +4 -0
- data/test/models/cart.rb +5 -0
- data/test/models/cat.rb +12 -0
- data/test/models/categorization.rb +21 -0
- data/test/models/category.rb +47 -0
- data/test/models/chef.rb +10 -0
- data/test/models/citation.rb +7 -0
- data/test/models/club.rb +28 -0
- data/test/models/college.rb +12 -0
- data/test/models/column.rb +5 -0
- data/test/models/column_name.rb +5 -0
- data/test/models/comment.rb +98 -0
- data/test/models/company.rb +226 -0
- data/test/models/company_in_module.rb +99 -0
- data/test/models/computer.rb +5 -0
- data/test/models/contact.rb +43 -0
- data/test/models/content.rb +42 -0
- data/test/models/contract.rb +38 -0
- data/test/models/country.rb +5 -0
- data/test/models/course.rb +8 -0
- data/test/models/customer.rb +85 -0
- data/test/models/customer_carrier.rb +16 -0
- data/test/models/dashboard.rb +5 -0
- data/test/models/default.rb +4 -0
- data/test/models/department.rb +6 -0
- data/test/models/destroy_async_parent.rb +15 -0
- data/test/models/destroy_async_parent_soft_delete.rb +20 -0
- data/test/models/developer.rb +341 -0
- data/test/models/dl_keyed_belongs_to.rb +13 -0
- data/test/models/dl_keyed_belongs_to_soft_delete.rb +19 -0
- data/test/models/dl_keyed_has_many.rb +5 -0
- data/test/models/dl_keyed_has_many_through.rb +5 -0
- data/test/models/dl_keyed_has_one.rb +5 -0
- data/test/models/dl_keyed_join.rb +10 -0
- data/test/models/dog.rb +7 -0
- data/test/models/dog_lover.rb +7 -0
- data/test/models/doubloon.rb +14 -0
- data/test/models/drink_designer.rb +20 -0
- data/test/models/edge.rb +7 -0
- data/test/models/electron.rb +7 -0
- data/test/models/engine.rb +5 -0
- data/test/models/entrant.rb +5 -0
- data/test/models/entry.rb +5 -0
- data/test/models/essay.rb +8 -0
- data/test/models/essay_destroy_async.rb +12 -0
- data/test/models/event.rb +5 -0
- data/test/models/eye.rb +39 -0
- data/test/models/face.rb +17 -0
- data/test/models/family.rb +6 -0
- data/test/models/family_tree.rb +6 -0
- data/test/models/friendship.rb +8 -0
- data/test/models/frog.rb +8 -0
- data/test/models/guid.rb +4 -0
- data/test/models/guitar.rb +6 -0
- data/test/models/hotel.rb +13 -0
- data/test/models/human.rb +39 -0
- data/test/models/image.rb +5 -0
- data/test/models/interest.rb +16 -0
- data/test/models/invoice.rb +6 -0
- data/test/models/item.rb +9 -0
- data/test/models/job.rb +9 -0
- data/test/models/joke.rb +9 -0
- data/test/models/keyboard.rb +5 -0
- data/test/models/legacy_thing.rb +5 -0
- data/test/models/lesson.rb +13 -0
- data/test/models/line_item.rb +5 -0
- data/test/models/liquid.rb +6 -0
- data/test/models/man.rb +11 -0
- data/test/models/matey.rb +6 -0
- data/test/models/measurement.rb +4 -0
- data/test/models/member.rb +45 -0
- data/test/models/member_detail.rb +11 -0
- data/test/models/member_type.rb +5 -0
- data/test/models/membership.rb +38 -0
- data/test/models/mentor.rb +5 -0
- data/test/models/message.rb +5 -0
- data/test/models/minimalistic.rb +4 -0
- data/test/models/minivan.rb +10 -0
- data/test/models/mixed_case_monkey.rb +5 -0
- data/test/models/mocktail_designer.rb +2 -0
- data/test/models/molecule.rb +8 -0
- data/test/models/mouse.rb +6 -0
- data/test/models/movie.rb +7 -0
- data/test/models/node.rb +7 -0
- data/test/models/non_primary_key.rb +4 -0
- data/test/models/notification.rb +5 -0
- data/test/models/numeric_data.rb +12 -0
- data/test/models/order.rb +6 -0
- data/test/models/organization.rb +16 -0
- data/test/models/other_dog.rb +7 -0
- data/test/models/owner.rb +39 -0
- data/test/models/parrot.rb +36 -0
- data/test/models/person.rb +147 -0
- data/test/models/personal_legacy_thing.rb +6 -0
- data/test/models/pet.rb +20 -0
- data/test/models/pet_treasure.rb +8 -0
- data/test/models/pirate.rb +116 -0
- data/test/models/possession.rb +5 -0
- data/test/models/post.rb +371 -0
- data/test/models/price_estimate.rb +14 -0
- data/test/models/professor.rb +7 -0
- data/test/models/project.rb +42 -0
- data/test/models/publisher/article.rb +6 -0
- data/test/models/publisher/magazine.rb +5 -0
- data/test/models/publisher.rb +4 -0
- data/test/models/randomly_named_c1.rb +5 -0
- data/test/models/rating.rb +8 -0
- data/test/models/reader.rb +25 -0
- data/test/models/recipe.rb +5 -0
- data/test/models/record.rb +4 -0
- data/test/models/reference.rb +25 -0
- data/test/models/reply.rb +79 -0
- data/test/models/room.rb +6 -0
- data/test/models/section.rb +6 -0
- data/test/models/seminar.rb +6 -0
- data/test/models/session.rb +6 -0
- data/test/models/ship.rb +42 -0
- data/test/models/ship_part.rb +10 -0
- data/test/models/shop.rb +19 -0
- data/test/models/shop_account.rb +8 -0
- data/test/models/speedometer.rb +8 -0
- data/test/models/sponsor.rb +10 -0
- data/test/models/squeak.rb +6 -0
- data/test/models/strict_zine.rb +7 -0
- data/test/models/string_key_object.rb +5 -0
- data/test/models/student.rb +6 -0
- data/test/models/subject.rb +16 -0
- data/test/models/subscriber.rb +10 -0
- data/test/models/subscription.rb +8 -0
- data/test/models/tag.rb +16 -0
- data/test/models/tagging.rb +20 -0
- data/test/models/task.rb +7 -0
- data/test/models/topic.rb +153 -0
- data/test/models/toy.rb +10 -0
- data/test/models/traffic_light.rb +6 -0
- data/test/models/treasure.rb +16 -0
- data/test/models/treaty.rb +5 -0
- data/test/models/tree.rb +5 -0
- data/test/models/tuning_peg.rb +6 -0
- data/test/models/tyre.rb +13 -0
- data/test/models/user.rb +22 -0
- data/test/models/uuid_child.rb +5 -0
- data/test/models/uuid_item.rb +8 -0
- data/test/models/uuid_parent.rb +5 -0
- data/test/models/vegetables.rb +33 -0
- data/test/models/vehicle.rb +7 -0
- data/test/models/vertex.rb +11 -0
- data/test/models/warehouse_thing.rb +7 -0
- data/test/models/wheel.rb +5 -0
- data/test/models/without_table.rb +5 -0
- data/test/models/zine.rb +5 -0
- data/test/schema/i5/ibm_db_specific_schema.rb +137 -0
- data/test/schema/ids/ibm_db_specific_schema.rb +140 -0
- data/test/schema/luw/ibm_db_specific_schema.rb +137 -0
- data/test/schema/mysql2_specific_schema.rb +82 -0
- data/test/schema/oracle_specific_schema.rb +38 -0
- data/test/schema/postgresql_specific_schema.rb +125 -0
- data/test/schema/schema.rb +1237 -0
- data/test/schema/schema.rb.original +1057 -0
- data/test/schema/sqlite_specific_schema.rb +11 -0
- data/test/schema/zOS/ibm_db_specific_schema.rb +208 -0
- data/test/support/config.rb +43 -0
- data/test/support/connection.rb +29 -0
- data/test/support/connection_helper.rb +16 -0
- data/test/support/ddl_helper.rb +10 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/legacy_6_0_record_mysql.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/legacy_relation.dump +0 -0
- data/test/support/schema_dumping_helper.rb +22 -0
- data/test/support/stubs/strong_parameters.rb +40 -0
- data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
- data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
- data/test/support/yaml_compatibility_fixtures/rails_v1_mysql.yml +206 -0
- data/test/support/yaml_compatibility_fixtures/rails_v2.yml +55 -0
- metadata +876 -0
@@ -0,0 +1,1580 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cases/helper"
|
4
|
+
require "models/post"
|
5
|
+
require "models/person"
|
6
|
+
require "models/reference"
|
7
|
+
require "models/job"
|
8
|
+
require "models/reader"
|
9
|
+
require "models/comment"
|
10
|
+
require "models/rating"
|
11
|
+
require "models/tag"
|
12
|
+
require "models/tagging"
|
13
|
+
require "models/author"
|
14
|
+
require "models/owner"
|
15
|
+
require "models/pet"
|
16
|
+
require "models/pet_treasure"
|
17
|
+
require "models/toy"
|
18
|
+
require "models/treasure"
|
19
|
+
require "models/contract"
|
20
|
+
require "models/company"
|
21
|
+
require "models/developer"
|
22
|
+
require "models/computer"
|
23
|
+
require "models/subscriber"
|
24
|
+
require "models/book"
|
25
|
+
require "models/subscription"
|
26
|
+
require "models/essay"
|
27
|
+
require "models/category"
|
28
|
+
require "models/categorization"
|
29
|
+
require "models/member"
|
30
|
+
require "models/membership"
|
31
|
+
require "models/club"
|
32
|
+
require "models/organization"
|
33
|
+
require "models/user"
|
34
|
+
require "models/family"
|
35
|
+
require "models/family_tree"
|
36
|
+
require "models/section"
|
37
|
+
require "models/seminar"
|
38
|
+
require "models/session"
|
39
|
+
|
40
|
+
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
41
|
+
fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
|
42
|
+
:owners, :pets, :toys, :jobs, :references, :companies, :members, :author_addresses,
|
43
|
+
:subscribers, :books, :subscriptions, :developers, :categorizations, :essays,
|
44
|
+
:categories_posts, :clubs, :memberships, :organizations, :author_favorites
|
45
|
+
|
46
|
+
# Dummies to force column loads so query counts are clean.
|
47
|
+
def setup
|
48
|
+
Person.create first_name: "gummy"
|
49
|
+
Reader.create person_id: 0, post_id: 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_has_many_through_create_record
|
53
|
+
assert books(:awdr).subscribers.create!(nick: "bob")
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_marshal_dump
|
57
|
+
preloaded = Post.includes(:first_blue_tags).first
|
58
|
+
assert_equal preloaded, Marshal.load(Marshal.dump(preloaded))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_through_association_with_joins
|
62
|
+
assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.joins(:comments))
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_through_association_with_left_joins
|
66
|
+
assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.left_joins(:comments))
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_through_association_with_through_scope_and_nested_where
|
70
|
+
company = Company.create!(name: "special")
|
71
|
+
developer = SpecialDeveloper.create!
|
72
|
+
SpecialContract.create!(company: company, special_developer: developer)
|
73
|
+
|
74
|
+
assert_equal [developer], company.special_developers.where.not("contracts.id": nil)
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_preload_with_nested_association
|
78
|
+
posts = Post.where(id: [authors(:david).id, authors(:mary).id]).
|
79
|
+
preload(:author, :author_favorites_with_scope).order(:id).to_a
|
80
|
+
|
81
|
+
assert_no_queries do
|
82
|
+
posts.each(&:author)
|
83
|
+
posts.each(&:author_favorites_with_scope)
|
84
|
+
assert_equal 1, posts[0].author_favorites_with_scope.length
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_preload_sti_rhs_class
|
89
|
+
developers = Developer.includes(:firms).all.to_a
|
90
|
+
assert_no_queries do
|
91
|
+
developers.each(&:firms)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_preload_sti_middle_relation
|
96
|
+
club = Club.create!(name: "Aaron cool banana club")
|
97
|
+
member1 = Member.create!(name: "Aaron")
|
98
|
+
member2 = Member.create!(name: "Cat")
|
99
|
+
|
100
|
+
SuperMembership.create! club: club, member: member1
|
101
|
+
CurrentMembership.create! club: club, member: member2
|
102
|
+
|
103
|
+
club1 = Club.includes(:members).find_by_id club.id
|
104
|
+
assert_equal [member1, member2].sort_by(&:id),
|
105
|
+
club1.members.sort_by(&:id)
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_preload_multiple_instances_of_the_same_record
|
109
|
+
club = Club.create!(name: "Aaron cool banana club")
|
110
|
+
Membership.create! club: club, member: Member.create!(name: "Aaron")
|
111
|
+
Membership.create! club: club, member: Member.create!(name: "Bob")
|
112
|
+
|
113
|
+
preloaded_clubs = Club.joins(:memberships).preload(:membership).to_a
|
114
|
+
assert_no_queries { preloaded_clubs.each(&:membership) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_ordered_has_many_through
|
118
|
+
person_prime = Class.new(ActiveRecord::Base) do
|
119
|
+
def self.name; "Person"; end
|
120
|
+
|
121
|
+
has_many :readers
|
122
|
+
has_many :posts, -> { order("posts.id DESC") }, through: :readers
|
123
|
+
end
|
124
|
+
posts = person_prime.includes(:posts).first.posts
|
125
|
+
|
126
|
+
assert_operator posts.length, :>, 1
|
127
|
+
posts.each_cons(2) do |left, right|
|
128
|
+
assert_operator left.id, :>, right.id
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_singleton_has_many_through
|
133
|
+
book = make_model "Book"
|
134
|
+
subscription = make_model "Subscription"
|
135
|
+
subscriber = make_model "Subscriber"
|
136
|
+
|
137
|
+
subscriber.primary_key = "nick"
|
138
|
+
subscription.belongs_to :book, anonymous_class: book
|
139
|
+
subscription.belongs_to :subscriber, anonymous_class: subscriber
|
140
|
+
|
141
|
+
book.has_many :subscriptions, anonymous_class: subscription
|
142
|
+
book.has_many :subscribers, through: :subscriptions, anonymous_class: subscriber
|
143
|
+
|
144
|
+
anonbook = book.first
|
145
|
+
namebook = Book.find anonbook.id
|
146
|
+
|
147
|
+
assert_operator anonbook.subscribers.count, :>, 0
|
148
|
+
anonbook.subscribers.each do |s|
|
149
|
+
assert_instance_of subscriber, s
|
150
|
+
end
|
151
|
+
assert_equal namebook.subscribers.map(&:id).sort,
|
152
|
+
anonbook.subscribers.map(&:id).sort
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_no_pk_join_table_append
|
156
|
+
lesson, _, student = make_no_pk_hm_t
|
157
|
+
|
158
|
+
sicp = lesson.new(name: "SICP")
|
159
|
+
ben = student.new(name: "Ben Bitdiddle")
|
160
|
+
sicp.students << ben
|
161
|
+
assert sicp.save!
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_no_pk_join_table_delete
|
165
|
+
lesson, lesson_student, student = make_no_pk_hm_t
|
166
|
+
|
167
|
+
sicp = lesson.new(name: "SICP")
|
168
|
+
ben = student.new(name: "Ben Bitdiddle")
|
169
|
+
louis = student.new(name: "Louis Reasoner")
|
170
|
+
sicp.students << ben
|
171
|
+
sicp.students << louis
|
172
|
+
assert sicp.save!
|
173
|
+
|
174
|
+
sicp.students.reload
|
175
|
+
assert_operator lesson_student.count, :>=, 2
|
176
|
+
assert_no_difference("student.count") do
|
177
|
+
assert_difference("lesson_student.count", -2) do
|
178
|
+
sicp.students.destroy(*student.all.to_a)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_no_pk_join_model_callbacks
|
184
|
+
lesson, lesson_student, student = make_no_pk_hm_t
|
185
|
+
|
186
|
+
after_destroy_called = false
|
187
|
+
lesson_student.after_destroy do
|
188
|
+
after_destroy_called = true
|
189
|
+
end
|
190
|
+
|
191
|
+
sicp = lesson.new(name: "SICP")
|
192
|
+
ben = student.new(name: "Ben Bitdiddle")
|
193
|
+
sicp.students << ben
|
194
|
+
assert sicp.save!
|
195
|
+
|
196
|
+
sicp.students.reload
|
197
|
+
sicp.students.destroy(*student.all.to_a)
|
198
|
+
assert after_destroy_called, "after destroy should be called"
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_pk_is_not_required_for_join
|
202
|
+
post = Post.includes(:scategories).first
|
203
|
+
post2 = Post.includes(:categories).first
|
204
|
+
|
205
|
+
assert_operator post.categories.length, :>, 0
|
206
|
+
assert_equal post2.categories.sort_by(&:id), post.categories.sort_by(&:id)
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_include?
|
210
|
+
person = Person.new
|
211
|
+
post = Post.new
|
212
|
+
person.posts << post
|
213
|
+
assert_includes person.posts, post
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_associate_existing
|
217
|
+
post = posts(:thinking)
|
218
|
+
person = people(:david)
|
219
|
+
|
220
|
+
assert_queries(1) do
|
221
|
+
post.people << person
|
222
|
+
end
|
223
|
+
|
224
|
+
assert_queries(1) do
|
225
|
+
assert_includes post.people, person
|
226
|
+
end
|
227
|
+
|
228
|
+
assert_includes post.reload.people.reload, person
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_delete_all_for_with_dependent_option_destroy
|
232
|
+
person = people(:david)
|
233
|
+
assert_equal 1, person.jobs_with_dependent_destroy.count
|
234
|
+
|
235
|
+
assert_no_difference "Job.count" do
|
236
|
+
assert_difference "Reference.count", -1 do
|
237
|
+
assert_equal 1, person.reload.jobs_with_dependent_destroy.delete_all
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_delete_all_for_with_dependent_option_nullify
|
243
|
+
person = people(:david)
|
244
|
+
assert_equal 1, person.jobs_with_dependent_nullify.count
|
245
|
+
|
246
|
+
assert_no_difference "Job.count" do
|
247
|
+
assert_no_difference "Reference.count" do
|
248
|
+
assert_equal 1, person.reload.jobs_with_dependent_nullify.delete_all
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_delete_all_for_with_dependent_option_delete_all
|
254
|
+
person = people(:david)
|
255
|
+
assert_equal 1, person.jobs_with_dependent_delete_all.count
|
256
|
+
|
257
|
+
assert_no_difference "Job.count" do
|
258
|
+
assert_difference "Reference.count", -1 do
|
259
|
+
assert_equal 1, person.reload.jobs_with_dependent_delete_all.delete_all
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_delete_all_on_association_clears_scope
|
265
|
+
post = Post.create!(title: "Rails 6", body: "")
|
266
|
+
people = post.people
|
267
|
+
people.create!(first_name: "Jeb")
|
268
|
+
people.delete_all
|
269
|
+
assert_nil people.first
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_concat
|
273
|
+
person = people(:david)
|
274
|
+
post = posts(:thinking)
|
275
|
+
result = post.people.concat [person]
|
276
|
+
assert_equal 1, post.people.size
|
277
|
+
assert_equal 1, post.people.reload.size
|
278
|
+
assert_equal post.people, result
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_associate_existing_record_twice_should_add_to_target_twice
|
282
|
+
post = posts(:thinking)
|
283
|
+
person = people(:david)
|
284
|
+
|
285
|
+
assert_difference "post.people.to_a.count", 2 do
|
286
|
+
post.people << person
|
287
|
+
post.people << person
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_associate_existing_record_twice_should_add_records_twice
|
292
|
+
post = posts(:thinking)
|
293
|
+
person = people(:david)
|
294
|
+
|
295
|
+
assert_difference "post.people.count", 2 do
|
296
|
+
post.people << person
|
297
|
+
post.people << person
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_add_two_instance_and_then_deleting
|
302
|
+
post = posts(:thinking)
|
303
|
+
person = people(:david)
|
304
|
+
|
305
|
+
post.people << person
|
306
|
+
post.people << person
|
307
|
+
|
308
|
+
counts = ["post.people.count", "post.people.to_a.count", "post.readers.count", "post.readers.to_a.count"]
|
309
|
+
assert_difference counts, -2 do
|
310
|
+
post.people.delete(person)
|
311
|
+
end
|
312
|
+
|
313
|
+
assert_not_includes post.people.reload, person
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_associating_new
|
317
|
+
assert_queries(1) { posts(:thinking) }
|
318
|
+
new_person = nil # so block binding catches it
|
319
|
+
|
320
|
+
assert_queries(0) do
|
321
|
+
new_person = Person.new first_name: "bob"
|
322
|
+
end
|
323
|
+
|
324
|
+
# Associating new records always saves them
|
325
|
+
# Thus, 1 query for the new person record, 1 query for the new join table record
|
326
|
+
assert_queries(2) do
|
327
|
+
posts(:thinking).people << new_person
|
328
|
+
end
|
329
|
+
|
330
|
+
assert_queries(1) do
|
331
|
+
assert_includes posts(:thinking).people, new_person
|
332
|
+
end
|
333
|
+
|
334
|
+
assert_includes posts(:thinking).reload.people.reload, new_person
|
335
|
+
end
|
336
|
+
|
337
|
+
def test_associate_new_by_building
|
338
|
+
assert_queries(1) { posts(:thinking) }
|
339
|
+
|
340
|
+
assert_queries(0) do
|
341
|
+
posts(:thinking).people.build(first_name: "Bob")
|
342
|
+
posts(:thinking).people.new(first_name: "Ted")
|
343
|
+
end
|
344
|
+
|
345
|
+
# Should only need to load the association once
|
346
|
+
assert_queries(1) do
|
347
|
+
assert_includes posts(:thinking).people.collect(&:first_name), "Bob"
|
348
|
+
assert_includes posts(:thinking).people.collect(&:first_name), "Ted"
|
349
|
+
end
|
350
|
+
|
351
|
+
# 2 queries for each new record (1 to save the record itself, 1 for the join model)
|
352
|
+
# * 2 new records = 4
|
353
|
+
# + 1 query to save the actual post = 5
|
354
|
+
assert_queries(5) do
|
355
|
+
posts(:thinking).body += "-changed"
|
356
|
+
posts(:thinking).save
|
357
|
+
end
|
358
|
+
|
359
|
+
assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Bob"
|
360
|
+
assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Ted"
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_build_then_save_with_has_many_inverse
|
364
|
+
post = posts(:thinking)
|
365
|
+
person = post.people.build(first_name: "Bob")
|
366
|
+
person.save
|
367
|
+
post.reload
|
368
|
+
|
369
|
+
assert_includes post.people, person
|
370
|
+
end
|
371
|
+
|
372
|
+
def test_build_then_save_with_has_one_inverse
|
373
|
+
post = posts(:thinking)
|
374
|
+
person = post.single_people.build(first_name: "Bob")
|
375
|
+
person.save
|
376
|
+
post.reload
|
377
|
+
|
378
|
+
assert_includes post.single_people, person
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_build_then_remove_then_save
|
382
|
+
post = posts(:thinking)
|
383
|
+
post.people.build(first_name: "Bob")
|
384
|
+
ted = post.people.build(first_name: "Ted")
|
385
|
+
post.people.delete(ted)
|
386
|
+
post.save!
|
387
|
+
post.reload
|
388
|
+
|
389
|
+
assert_equal ["Bob"], post.people.collect(&:first_name)
|
390
|
+
end
|
391
|
+
|
392
|
+
def test_both_parent_ids_set_when_saving_new
|
393
|
+
post = Post.new(title: "Hello", body: "world")
|
394
|
+
person = Person.new(first_name: "Sean")
|
395
|
+
|
396
|
+
post.people = [person]
|
397
|
+
post.save
|
398
|
+
|
399
|
+
assert post.id
|
400
|
+
assert person.id
|
401
|
+
assert_equal post.id, post.readers.first.post_id
|
402
|
+
assert_equal person.id, post.readers.first.person_id
|
403
|
+
end
|
404
|
+
|
405
|
+
def test_delete_association
|
406
|
+
assert_queries(2) { posts(:welcome); people(:michael); }
|
407
|
+
|
408
|
+
assert_queries(1) do
|
409
|
+
posts(:welcome).people.delete(people(:michael))
|
410
|
+
end
|
411
|
+
|
412
|
+
assert_queries(1) do
|
413
|
+
assert_empty posts(:welcome).people
|
414
|
+
end
|
415
|
+
|
416
|
+
assert_empty posts(:welcome).reload.people.reload
|
417
|
+
end
|
418
|
+
|
419
|
+
def test_destroy_association
|
420
|
+
assert_no_difference "Person.count" do
|
421
|
+
assert_difference "Reader.count", -1 do
|
422
|
+
posts(:welcome).people.destroy(people(:michael))
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
assert_empty posts(:welcome).reload.people
|
427
|
+
assert_empty posts(:welcome).people.reload
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_destroy_all
|
431
|
+
assert_no_difference "Person.count" do
|
432
|
+
assert_difference "Reader.count", -1 do
|
433
|
+
posts(:welcome).people.destroy_all
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
assert_empty posts(:welcome).reload.people
|
438
|
+
assert_empty posts(:welcome).people.reload
|
439
|
+
end
|
440
|
+
|
441
|
+
def test_destroy_all_on_association_clears_scope
|
442
|
+
post = Post.create!(title: "Rails 6", body: "")
|
443
|
+
people = post.people
|
444
|
+
people.create!(first_name: "Jeb")
|
445
|
+
people.destroy_all
|
446
|
+
assert_nil people.first
|
447
|
+
end
|
448
|
+
|
449
|
+
def test_destroy_on_association_clears_scope
|
450
|
+
post = Post.create!(title: "Rails 6", body: "")
|
451
|
+
people = post.people
|
452
|
+
person = people.create!(first_name: "Jeb")
|
453
|
+
people.destroy(person)
|
454
|
+
assert_nil people.first
|
455
|
+
end
|
456
|
+
|
457
|
+
def test_delete_on_association_clears_scope
|
458
|
+
post = Post.create!(title: "Rails 6", body: "")
|
459
|
+
people = post.people
|
460
|
+
person = people.create!(first_name: "Jeb")
|
461
|
+
people.delete(person)
|
462
|
+
assert_nil people.first
|
463
|
+
end
|
464
|
+
|
465
|
+
def test_should_raise_exception_for_destroying_mismatching_records
|
466
|
+
assert_no_difference ["Person.count", "Reader.count"] do
|
467
|
+
assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:welcome).people.destroy(posts(:thinking)) }
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def test_delete_through_belongs_to_with_dependent_nullify
|
472
|
+
Reference.make_comments = true
|
473
|
+
|
474
|
+
person = people(:michael)
|
475
|
+
job = jobs(:magician)
|
476
|
+
reference = Reference.where(job_id: job.id, person_id: person.id).first
|
477
|
+
|
478
|
+
assert_no_difference ["Job.count", "Reference.count"] do
|
479
|
+
assert_difference "person.jobs.count", -1 do
|
480
|
+
person.jobs_with_dependent_nullify.delete(job)
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
assert_nil reference.reload.job_id
|
485
|
+
ensure
|
486
|
+
Reference.make_comments = false
|
487
|
+
end
|
488
|
+
|
489
|
+
def test_delete_through_belongs_to_with_dependent_delete_all
|
490
|
+
Reference.make_comments = true
|
491
|
+
|
492
|
+
person = people(:michael)
|
493
|
+
job = jobs(:magician)
|
494
|
+
|
495
|
+
# Make sure we're not deleting everything
|
496
|
+
assert person.jobs.count >= 2
|
497
|
+
|
498
|
+
assert_no_difference "Job.count" do
|
499
|
+
assert_difference ["person.jobs.count", "Reference.count"], -1 do
|
500
|
+
person.jobs_with_dependent_delete_all.delete(job)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
# Check that the destroy callback on Reference did not run
|
505
|
+
assert_nil person.reload.comments
|
506
|
+
ensure
|
507
|
+
Reference.make_comments = false
|
508
|
+
end
|
509
|
+
|
510
|
+
def test_delete_through_belongs_to_with_dependent_destroy
|
511
|
+
Reference.make_comments = true
|
512
|
+
|
513
|
+
person = people(:michael)
|
514
|
+
job = jobs(:magician)
|
515
|
+
|
516
|
+
# Make sure we're not deleting everything
|
517
|
+
assert person.jobs.count >= 2
|
518
|
+
|
519
|
+
assert_no_difference "Job.count" do
|
520
|
+
assert_difference ["person.jobs.count", "Reference.count"], -1 do
|
521
|
+
person.jobs_with_dependent_destroy.delete(job)
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
# Check that the destroy callback on Reference ran
|
526
|
+
assert_equal "Reference destroyed", person.reload.comments
|
527
|
+
ensure
|
528
|
+
Reference.make_comments = false
|
529
|
+
end
|
530
|
+
|
531
|
+
def test_belongs_to_with_dependent_destroy
|
532
|
+
person = PersonWithDependentDestroyJobs.find(1)
|
533
|
+
|
534
|
+
# Create a reference which is not linked to a job. This should not be destroyed.
|
535
|
+
person.references.create!
|
536
|
+
|
537
|
+
assert_no_difference "Job.count" do
|
538
|
+
assert_difference "Reference.count", -person.jobs.count do
|
539
|
+
person.destroy
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
def test_belongs_to_with_dependent_delete_all
|
545
|
+
person = PersonWithDependentDeleteAllJobs.find(1)
|
546
|
+
|
547
|
+
# Create a reference which is not linked to a job. This should not be destroyed.
|
548
|
+
person.references.create!
|
549
|
+
|
550
|
+
assert_no_difference "Job.count" do
|
551
|
+
assert_difference "Reference.count", -person.jobs.count do
|
552
|
+
person.destroy
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
def test_belongs_to_with_dependent_nullify
|
558
|
+
person = PersonWithDependentNullifyJobs.find(1)
|
559
|
+
|
560
|
+
references = person.references.to_a
|
561
|
+
|
562
|
+
assert_no_difference ["Reference.count", "Job.count"] do
|
563
|
+
person.destroy
|
564
|
+
end
|
565
|
+
|
566
|
+
references.each do |reference|
|
567
|
+
assert_nil reference.reload.job_id
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def test_update_counter_caches_on_delete
|
572
|
+
post = posts(:welcome)
|
573
|
+
tag = post.tags.create!(name: "doomed")
|
574
|
+
|
575
|
+
assert_difference ["post.reload.tags_count"], -1 do
|
576
|
+
posts(:welcome).tags.delete(tag)
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
def test_update_counter_caches_on_delete_with_dependent_destroy
|
581
|
+
post = posts(:welcome)
|
582
|
+
tag = post.tags.create!(name: "doomed")
|
583
|
+
post.update_columns(tags_with_destroy_count: post.tags.count)
|
584
|
+
|
585
|
+
assert_difference ["post.reload.tags_with_destroy_count"], -1 do
|
586
|
+
posts(:welcome).tags_with_destroy.delete(tag)
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
def test_update_counter_caches_on_delete_with_dependent_nullify
|
591
|
+
post = posts(:welcome)
|
592
|
+
tag = post.tags.create!(name: "doomed")
|
593
|
+
post.update_columns(tags_with_nullify_count: post.tags.count)
|
594
|
+
|
595
|
+
assert_no_difference "post.reload.tags_count" do
|
596
|
+
assert_difference "post.reload.tags_with_nullify_count", -1 do
|
597
|
+
posts(:welcome).tags_with_nullify.delete(tag)
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
def test_update_counter_caches_on_replace_association
|
603
|
+
post = posts(:welcome)
|
604
|
+
tag = post.tags.create!(name: "doomed")
|
605
|
+
tag.tagged_posts << posts(:thinking)
|
606
|
+
|
607
|
+
tag.tagged_posts = []
|
608
|
+
post.reload
|
609
|
+
|
610
|
+
assert_equal(post.taggings.count, post.tags_count)
|
611
|
+
end
|
612
|
+
|
613
|
+
def test_update_counter_caches_on_destroy
|
614
|
+
post = posts(:welcome)
|
615
|
+
tag = post.tags.create!(name: "doomed")
|
616
|
+
|
617
|
+
assert_difference "post.reload.tags_count", -1 do
|
618
|
+
tag.tagged_posts.destroy(post)
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
def test_update_counter_caches_on_destroy_with_indestructible_through_record
|
623
|
+
post = posts(:welcome)
|
624
|
+
tag = post.indestructible_tags.create!(name: "doomed")
|
625
|
+
post.update_columns(indestructible_tags_count: post.indestructible_tags.count)
|
626
|
+
|
627
|
+
assert_no_difference "post.reload.indestructible_tags_count" do
|
628
|
+
posts(:welcome).indestructible_tags.destroy(tag)
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
632
|
+
def test_replace_association
|
633
|
+
assert_queries(4) { posts(:welcome); people(:david); people(:michael); posts(:welcome).people.reload }
|
634
|
+
|
635
|
+
# 1 query to delete the existing reader (michael)
|
636
|
+
# 1 query to associate the new reader (david)
|
637
|
+
assert_queries(2) do
|
638
|
+
posts(:welcome).people = [people(:david)]
|
639
|
+
end
|
640
|
+
|
641
|
+
assert_no_queries do
|
642
|
+
assert_includes posts(:welcome).people, people(:david)
|
643
|
+
assert_not_includes posts(:welcome).people, people(:michael)
|
644
|
+
end
|
645
|
+
|
646
|
+
assert_includes posts(:welcome).reload.people.reload, people(:david)
|
647
|
+
assert_not_includes posts(:welcome).reload.people.reload, people(:michael)
|
648
|
+
end
|
649
|
+
|
650
|
+
def test_replace_association_with_duplicates
|
651
|
+
post = posts(:thinking)
|
652
|
+
person = people(:david)
|
653
|
+
|
654
|
+
assert_difference "post.people.count", 2 do
|
655
|
+
post.people = [person]
|
656
|
+
post.people = [person, person]
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
def test_replace_order_is_preserved
|
661
|
+
posts(:welcome).people.clear
|
662
|
+
posts(:welcome).people = [people(:david), people(:michael)]
|
663
|
+
assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order("id").map(&:person_id)
|
664
|
+
|
665
|
+
# Test the inverse order in case the first success was a coincidence
|
666
|
+
posts(:welcome).people.clear
|
667
|
+
posts(:welcome).people = [people(:michael), people(:david)]
|
668
|
+
assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order("id").map(&:person_id)
|
669
|
+
end
|
670
|
+
|
671
|
+
def test_replace_by_id_order_is_preserved
|
672
|
+
posts(:welcome).people.clear
|
673
|
+
posts(:welcome).person_ids = [people(:david).id, people(:michael).id]
|
674
|
+
assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order("id").map(&:person_id)
|
675
|
+
|
676
|
+
# Test the inverse order in case the first success was a coincidence
|
677
|
+
posts(:welcome).people.clear
|
678
|
+
posts(:welcome).person_ids = [people(:michael).id, people(:david).id]
|
679
|
+
assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order("id").map(&:person_id)
|
680
|
+
end
|
681
|
+
|
682
|
+
def test_associate_with_create
|
683
|
+
assert_queries(1) { posts(:thinking) }
|
684
|
+
|
685
|
+
# 1 query for the new record, 1 for the join table record
|
686
|
+
# No need to update the actual collection yet!
|
687
|
+
assert_queries(2) do
|
688
|
+
posts(:thinking).people.create(first_name: "Jeb")
|
689
|
+
end
|
690
|
+
|
691
|
+
# *Now* we actually need the collection so it's loaded
|
692
|
+
assert_queries(1) do
|
693
|
+
assert_includes posts(:thinking).people.collect(&:first_name), "Jeb"
|
694
|
+
end
|
695
|
+
|
696
|
+
assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Jeb"
|
697
|
+
end
|
698
|
+
|
699
|
+
def test_through_record_is_built_when_created_with_where
|
700
|
+
assert_difference("posts(:thinking).readers.count", 1) do
|
701
|
+
posts(:thinking).people.where(readers: { skimmer: true }).create(first_name: "Jeb")
|
702
|
+
end
|
703
|
+
reader = posts(:thinking).readers.last
|
704
|
+
assert_equal true, reader.skimmer
|
705
|
+
end
|
706
|
+
|
707
|
+
def test_associate_with_create_and_no_options
|
708
|
+
peeps = posts(:thinking).people.count
|
709
|
+
posts(:thinking).people.create(first_name: "foo")
|
710
|
+
assert_equal peeps + 1, posts(:thinking).people.count
|
711
|
+
end
|
712
|
+
|
713
|
+
def test_associate_with_create_with_through_having_conditions
|
714
|
+
impatient_people = posts(:thinking).impatient_people.count
|
715
|
+
posts(:thinking).impatient_people.create!(first_name: "foo")
|
716
|
+
assert_equal impatient_people + 1, posts(:thinking).impatient_people.count
|
717
|
+
end
|
718
|
+
|
719
|
+
def test_associate_with_create_exclamation_and_no_options
|
720
|
+
peeps = posts(:thinking).people.count
|
721
|
+
posts(:thinking).people.create!(first_name: "foo")
|
722
|
+
assert_equal peeps + 1, posts(:thinking).people.count
|
723
|
+
end
|
724
|
+
|
725
|
+
def test_create_on_new_record
|
726
|
+
p = Post.new
|
727
|
+
|
728
|
+
error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create(first_name: "mew") }
|
729
|
+
assert_equal "You cannot call create unless the parent is saved", error.message
|
730
|
+
|
731
|
+
error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create!(first_name: "snow") }
|
732
|
+
assert_equal "You cannot call create unless the parent is saved", error.message
|
733
|
+
end
|
734
|
+
|
735
|
+
def test_associate_with_create_and_invalid_options
|
736
|
+
firm = companies(:first_firm)
|
737
|
+
assert_no_difference("firm.developers.count") { assert_nothing_raised { firm.developers.create(name: "0") } }
|
738
|
+
end
|
739
|
+
|
740
|
+
def test_associate_with_create_and_valid_options
|
741
|
+
firm = companies(:first_firm)
|
742
|
+
assert_difference("firm.developers.count", 1) { firm.developers.create(name: "developer") }
|
743
|
+
end
|
744
|
+
|
745
|
+
def test_associate_with_create_bang_and_invalid_options
|
746
|
+
firm = companies(:first_firm)
|
747
|
+
assert_no_difference("firm.developers.count") { assert_raises(ActiveRecord::RecordInvalid) { firm.developers.create!(name: "0") } }
|
748
|
+
end
|
749
|
+
|
750
|
+
def test_associate_with_create_bang_and_valid_options
|
751
|
+
firm = companies(:first_firm)
|
752
|
+
assert_difference("firm.developers.count", 1) { firm.developers.create!(name: "developer") }
|
753
|
+
end
|
754
|
+
|
755
|
+
def test_push_with_invalid_record
|
756
|
+
firm = companies(:first_firm)
|
757
|
+
assert_raises(ActiveRecord::RecordInvalid) { firm.developers << Developer.new(name: "0") }
|
758
|
+
end
|
759
|
+
|
760
|
+
def test_push_with_invalid_join_record
|
761
|
+
repair_validations(Contract) do
|
762
|
+
Contract.validate { |r| r.errors[:base] << "Invalid Contract" }
|
763
|
+
|
764
|
+
firm = companies(:first_firm)
|
765
|
+
lifo = Developer.new(name: "lifo")
|
766
|
+
assert_raises(ActiveRecord::RecordInvalid) do
|
767
|
+
assert_deprecated { firm.developers << lifo }
|
768
|
+
end
|
769
|
+
|
770
|
+
lifo = Developer.create!(name: "lifo")
|
771
|
+
assert_raises(ActiveRecord::RecordInvalid) do
|
772
|
+
assert_deprecated { firm.developers << lifo }
|
773
|
+
end
|
774
|
+
end
|
775
|
+
end
|
776
|
+
|
777
|
+
def test_clear_associations
|
778
|
+
assert_queries(2) { posts(:welcome); posts(:welcome).people.reload }
|
779
|
+
|
780
|
+
assert_queries(1) do
|
781
|
+
posts(:welcome).people.clear
|
782
|
+
end
|
783
|
+
|
784
|
+
assert_no_queries do
|
785
|
+
assert_empty posts(:welcome).people
|
786
|
+
end
|
787
|
+
|
788
|
+
assert_empty posts(:welcome).reload.people.reload
|
789
|
+
end
|
790
|
+
|
791
|
+
def test_association_callback_ordering
|
792
|
+
Post.reset_log
|
793
|
+
log = Post.log
|
794
|
+
post = posts(:thinking)
|
795
|
+
|
796
|
+
post.people_with_callbacks << people(:michael)
|
797
|
+
assert_equal [
|
798
|
+
[:added, :before, "Michael"],
|
799
|
+
[:added, :after, "Michael"]
|
800
|
+
], log.last(2)
|
801
|
+
|
802
|
+
post.people_with_callbacks.push(people(:david), Person.create!(first_name: "Bob"), Person.new(first_name: "Lary"))
|
803
|
+
assert_equal [
|
804
|
+
[:added, :before, "David"],
|
805
|
+
[:added, :after, "David"],
|
806
|
+
[:added, :before, "Bob"],
|
807
|
+
[:added, :after, "Bob"],
|
808
|
+
[:added, :before, "Lary"],
|
809
|
+
[:added, :after, "Lary"]
|
810
|
+
], log.last(6)
|
811
|
+
|
812
|
+
post.people_with_callbacks.build(first_name: "Ted")
|
813
|
+
assert_equal [
|
814
|
+
[:added, :before, "Ted"],
|
815
|
+
[:added, :after, "Ted"]
|
816
|
+
], log.last(2)
|
817
|
+
|
818
|
+
post.people_with_callbacks.create(first_name: "Sam")
|
819
|
+
assert_equal [
|
820
|
+
[:added, :before, "Sam"],
|
821
|
+
[:added, :after, "Sam"]
|
822
|
+
], log.last(2)
|
823
|
+
|
824
|
+
post.people_with_callbacks = [people(:michael), people(:david), Person.new(first_name: "Julian"), Person.create!(first_name: "Roger")]
|
825
|
+
assert_equal((%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort)
|
826
|
+
assert_equal [
|
827
|
+
[:added, :before, "Julian"],
|
828
|
+
[:added, :after, "Julian"],
|
829
|
+
[:added, :before, "Roger"],
|
830
|
+
[:added, :after, "Roger"]
|
831
|
+
], log.last(4)
|
832
|
+
|
833
|
+
post.people_with_callbacks.build { |person| person.first_name = "Ted" }
|
834
|
+
assert_equal [
|
835
|
+
[:added, :before, "Ted"],
|
836
|
+
[:added, :after, "Ted"]
|
837
|
+
], log.last(2)
|
838
|
+
|
839
|
+
post.people_with_callbacks.create { |person| person.first_name = "Sam" }
|
840
|
+
assert_equal [
|
841
|
+
[:added, :before, "Sam"],
|
842
|
+
[:added, :after, "Sam"]
|
843
|
+
], log.last(2)
|
844
|
+
end
|
845
|
+
|
846
|
+
def test_dynamic_find_should_respect_association_include
|
847
|
+
# SQL error in sort clause if :include is not included
|
848
|
+
# due to Unknown column 'comments.id'
|
849
|
+
assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title("Welcome to the weblog")
|
850
|
+
end
|
851
|
+
|
852
|
+
def test_count_with_include_should_alias_join_table
|
853
|
+
assert_equal 2, people(:michael).posts.includes(:readers).count
|
854
|
+
end
|
855
|
+
|
856
|
+
def test_inner_join_with_quoted_table_name
|
857
|
+
assert_equal 2, people(:michael).jobs.size
|
858
|
+
end
|
859
|
+
|
860
|
+
def test_get_ids
|
861
|
+
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
|
862
|
+
end
|
863
|
+
|
864
|
+
def test_get_ids_for_has_many_through_with_conditions_should_not_preload
|
865
|
+
Tagging.create!(taggable_type: "Post", taggable_id: posts(:welcome).id, tag: tags(:misc))
|
866
|
+
assert_not_called(ActiveRecord::Associations::Preloader, :new) do
|
867
|
+
posts(:welcome).misc_tag_ids
|
868
|
+
end
|
869
|
+
end
|
870
|
+
|
871
|
+
def test_get_ids_for_loaded_associations
|
872
|
+
person = people(:michael)
|
873
|
+
person.posts.reload
|
874
|
+
assert_no_queries do
|
875
|
+
person.post_ids
|
876
|
+
person.post_ids
|
877
|
+
end
|
878
|
+
end
|
879
|
+
|
880
|
+
def test_get_ids_for_unloaded_associations_does_not_load_them
|
881
|
+
person = people(:michael)
|
882
|
+
assert_not_predicate person.posts, :loaded?
|
883
|
+
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
|
884
|
+
assert_not_predicate person.posts, :loaded?
|
885
|
+
end
|
886
|
+
|
887
|
+
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
888
|
+
assert_called(Tag, :transaction) do
|
889
|
+
Post.first.tags.transaction do
|
890
|
+
# nothing
|
891
|
+
end
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
|
896
|
+
post = Post.create!(title: "TITLE", body: "BODY")
|
897
|
+
assert_equal [], post.author_favorites
|
898
|
+
end
|
899
|
+
|
900
|
+
def test_has_many_association_through_a_belongs_to_association
|
901
|
+
author = authors(:mary)
|
902
|
+
post = Post.create!(author: author, title: "TITLE", body: "BODY")
|
903
|
+
author.author_favorites.create(favorite_author_id: 1)
|
904
|
+
author.author_favorites.create(favorite_author_id: 2)
|
905
|
+
author.author_favorites.create(favorite_author_id: 3)
|
906
|
+
assert_equal post.author.author_favorites, post.author_favorites
|
907
|
+
end
|
908
|
+
|
909
|
+
def test_merge_join_association_with_has_many_through_association_proxy
|
910
|
+
author = authors(:mary)
|
911
|
+
assert_nothing_raised { author.comments.ratings.to_sql }
|
912
|
+
end
|
913
|
+
|
914
|
+
def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
|
915
|
+
assert_equal 2, owners(:blackbeard).toys.count
|
916
|
+
end
|
917
|
+
|
918
|
+
def test_find_on_has_many_association_collection_with_include_and_conditions
|
919
|
+
post_with_no_comments = people(:michael).posts_with_no_comments.first
|
920
|
+
assert_equal post_with_no_comments, posts(:authorless)
|
921
|
+
end
|
922
|
+
|
923
|
+
def test_has_many_through_has_one_reflection
|
924
|
+
assert_equal [comments(:eager_sti_on_associations_vs_comment)], authors(:david).very_special_comments
|
925
|
+
end
|
926
|
+
|
927
|
+
def test_modifying_has_many_through_has_one_reflection_should_raise
|
928
|
+
[
|
929
|
+
lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(body: "Gorp!", post_id: 1011), VerySpecialComment.create!(body: "Eep!", post_id: 1012)] },
|
930
|
+
lambda { authors(:david).very_special_comments << VerySpecialComment.create!(body: "Hoohah!", post_id: 1013) },
|
931
|
+
lambda { authors(:david).very_special_comments.delete(authors(:david).very_special_comments.first) },
|
932
|
+
].each { |block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
|
933
|
+
end
|
934
|
+
|
935
|
+
def test_has_many_association_through_a_has_many_association_to_self
|
936
|
+
sarah = Person.create!(first_name: "Sarah", primary_contact_id: people(:susan).id, gender: "F", number1_fan_id: 1)
|
937
|
+
john = Person.create!(first_name: "John", primary_contact_id: sarah.id, gender: "M", number1_fan_id: 1)
|
938
|
+
assert_equal sarah.agents, [john]
|
939
|
+
assert_equal people(:susan).agents.flat_map(&:agents).sort, people(:susan).agents_of_agents.sort
|
940
|
+
end
|
941
|
+
|
942
|
+
def test_associate_existing_with_nonstandard_primary_key_on_belongs_to
|
943
|
+
Categorization.create(author: authors(:mary), named_category_name: categories(:general).name)
|
944
|
+
assert_equal categories(:general), authors(:mary).named_categories.first
|
945
|
+
end
|
946
|
+
|
947
|
+
def test_collection_build_with_nonstandard_primary_key_on_belongs_to
|
948
|
+
author = authors(:mary)
|
949
|
+
category = author.named_categories.build(name: "Primary")
|
950
|
+
author.save
|
951
|
+
assert Categorization.exists?(author_id: author.id, named_category_name: category.name)
|
952
|
+
assert_includes author.named_categories.reload, category
|
953
|
+
end
|
954
|
+
|
955
|
+
def test_collection_create_with_nonstandard_primary_key_on_belongs_to
|
956
|
+
author = authors(:mary)
|
957
|
+
category = author.named_categories.create(name: "Primary")
|
958
|
+
assert Categorization.exists?(author_id: author.id, named_category_name: category.name)
|
959
|
+
assert_includes author.named_categories.reload, category
|
960
|
+
end
|
961
|
+
|
962
|
+
def test_collection_exists
|
963
|
+
author = authors(:mary)
|
964
|
+
category = Category.create!(author_ids: [author.id], name: "Primary")
|
965
|
+
assert category.authors.exists?(id: author.id)
|
966
|
+
assert category.reload.authors.exists?(id: author.id)
|
967
|
+
end
|
968
|
+
|
969
|
+
def test_collection_delete_with_nonstandard_primary_key_on_belongs_to
|
970
|
+
author = authors(:mary)
|
971
|
+
category = author.named_categories.create(name: "Primary")
|
972
|
+
author.named_categories.delete(category)
|
973
|
+
assert_not Categorization.exists?(author_id: author.id, named_category_name: category.name)
|
974
|
+
assert_empty author.named_categories.reload
|
975
|
+
end
|
976
|
+
|
977
|
+
def test_collection_singular_ids_getter_with_string_primary_keys
|
978
|
+
book = books(:awdr)
|
979
|
+
assert_equal 2, book.subscriber_ids.size
|
980
|
+
assert_equal [subscribers(:first).nick, subscribers(:second).nick].sort, book.subscriber_ids.sort
|
981
|
+
end
|
982
|
+
|
983
|
+
def test_collection_singular_ids_setter
|
984
|
+
company = companies(:rails_core)
|
985
|
+
dev = Developer.first
|
986
|
+
|
987
|
+
company.developer_ids = [dev.id]
|
988
|
+
assert_equal [dev], company.developers
|
989
|
+
end
|
990
|
+
|
991
|
+
def test_collection_singular_ids_setter_with_required_type_cast
|
992
|
+
company = companies(:rails_core)
|
993
|
+
dev = Developer.first
|
994
|
+
|
995
|
+
company.developer_ids = [dev.id.to_s]
|
996
|
+
assert_equal [dev], company.developers
|
997
|
+
end
|
998
|
+
|
999
|
+
def test_collection_singular_ids_setter_with_string_primary_keys
|
1000
|
+
assert_nothing_raised do
|
1001
|
+
book = books(:awdr)
|
1002
|
+
book.subscriber_ids = [subscribers(:second).nick]
|
1003
|
+
assert_equal [subscribers(:second)], book.subscribers.reload
|
1004
|
+
|
1005
|
+
book.subscriber_ids = []
|
1006
|
+
assert_equal [], book.subscribers.reload
|
1007
|
+
end
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set
|
1011
|
+
company = companies(:rails_core)
|
1012
|
+
ids = [Developer.first.id, -9999]
|
1013
|
+
e = assert_raises(ActiveRecord::RecordNotFound) { company.developer_ids = ids }
|
1014
|
+
msg = "Couldn't find all Developers with 'id': (1, -9999) (found 1 results, but was looking for 2). Couldn't find Developer with id -9999."
|
1015
|
+
assert_equal(msg, e.message)
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
def test_collection_singular_ids_through_setter_raises_exception_when_invalid_ids_set
|
1019
|
+
author = authors(:david)
|
1020
|
+
ids = [categories(:general).name, "Unknown"]
|
1021
|
+
e = assert_raises(ActiveRecord::RecordNotFound) { author.essay_category_ids = ids }
|
1022
|
+
msg = "Couldn't find all Categories with 'name': (General, Unknown) (found 1 results, but was looking for 2). Couldn't find Category with name Unknown."
|
1023
|
+
assert_equal msg, e.message
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
def test_build_a_model_from_hm_through_association_with_where_clause
|
1027
|
+
assert_nothing_raised { books(:awdr).subscribers.where(nick: "marklazz").build }
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_where_clause
|
1031
|
+
new_subscriber = books(:awdr).subscribers.where(nick: "marklazz").build
|
1032
|
+
assert_equal new_subscriber.nick, "marklazz"
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_multiple_where_clauses
|
1036
|
+
new_subscriber = books(:awdr).subscribers.where(nick: "marklazz").where(name: "Marcelo Giorgi").build
|
1037
|
+
assert_equal new_subscriber.nick, "marklazz"
|
1038
|
+
assert_equal new_subscriber.name, "Marcelo Giorgi"
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def test_include_method_in_association_through_should_return_true_for_instance_added_with_build
|
1042
|
+
person = Person.new
|
1043
|
+
reference = person.references.build
|
1044
|
+
job = reference.build_job
|
1045
|
+
assert_includes person.jobs, job
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
def test_include_method_in_association_through_should_return_true_for_instance_added_with_nested_builds
|
1049
|
+
author = Author.new
|
1050
|
+
post = author.posts.build
|
1051
|
+
comment = post.comments.build
|
1052
|
+
assert_includes author.comments, comment
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
def test_through_association_readonly_should_be_false
|
1056
|
+
assert_not_predicate people(:michael).posts.first, :readonly?
|
1057
|
+
assert_not_predicate people(:michael).posts.to_a.first, :readonly?
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
def test_can_update_through_association
|
1061
|
+
assert_nothing_raised do
|
1062
|
+
people(:michael).posts.first.update!(title: "Can write")
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def test_has_many_through_with_source_scope
|
1067
|
+
expected = [readers(:michael_welcome).becomes(LazyReader)]
|
1068
|
+
assert_equal expected, Author.first.lazy_readers_skimmers_or_not
|
1069
|
+
assert_equal expected, Author.preload(:lazy_readers_skimmers_or_not).first.lazy_readers_skimmers_or_not
|
1070
|
+
assert_equal expected, Author.eager_load(:lazy_readers_skimmers_or_not).first.lazy_readers_skimmers_or_not
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
def test_has_many_through_with_through_scope_with_includes
|
1074
|
+
expected = [readers(:bob_welcome).becomes(LazyReader)]
|
1075
|
+
assert_equal expected, Author.last.lazy_readers_skimmers_or_not_2
|
1076
|
+
assert_equal expected, Author.preload(:lazy_readers_skimmers_or_not_2).last.lazy_readers_skimmers_or_not_2
|
1077
|
+
assert_equal expected, Author.eager_load(:lazy_readers_skimmers_or_not_2).last.lazy_readers_skimmers_or_not_2
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
def test_has_many_through_with_through_scope_with_joins
|
1081
|
+
expected = [readers(:bob_welcome).becomes(LazyReader)]
|
1082
|
+
assert_equal expected, Author.last.lazy_readers_skimmers_or_not_3
|
1083
|
+
assert_equal expected, Author.preload(:lazy_readers_skimmers_or_not_3).last.lazy_readers_skimmers_or_not_3
|
1084
|
+
assert_equal expected, Author.eager_load(:lazy_readers_skimmers_or_not_3).last.lazy_readers_skimmers_or_not_3
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
def test_duplicated_has_many_through_with_through_scope_with_joins
|
1088
|
+
Categorization.create!(author: authors(:david), post: posts(:thinking), category: categories(:technology))
|
1089
|
+
|
1090
|
+
expected = [categorizations(:david_welcome_general)]
|
1091
|
+
assert_equal expected, Author.preload(:general_posts, :general_categorizations).first.general_categorizations
|
1092
|
+
assert_equal expected, Author.eager_load(:general_posts, :general_categorizations).first.general_categorizations
|
1093
|
+
|
1094
|
+
expected = [posts(:welcome)]
|
1095
|
+
assert_equal expected, Author.preload(:general_categorizations, :general_posts).first.general_posts
|
1096
|
+
assert_equal expected, Author.eager_load(:general_categorizations, :general_posts).first.general_posts
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
def test_has_many_through_polymorphic_with_rewhere
|
1100
|
+
post = TaggedPost.create!(title: "Tagged", body: "Post")
|
1101
|
+
tag = post.tags.create!(name: "Tag")
|
1102
|
+
assert_equal [tag], TaggedPost.preload(:tags).last.tags
|
1103
|
+
assert_equal [tag], TaggedPost.eager_load(:tags).last.tags
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
def test_has_many_through_polymorphic_with_primary_key_option
|
1107
|
+
assert_equal [categories(:general)], authors(:david).essay_categories
|
1108
|
+
|
1109
|
+
authors = Author.joins(:essay_categories).where("categories.id" => categories(:general).id)
|
1110
|
+
assert_equal authors(:david), authors.first
|
1111
|
+
|
1112
|
+
assert_equal [owners(:blackbeard)], authors(:david).essay_owners
|
1113
|
+
|
1114
|
+
authors = Author.joins(:essay_owners).where("owners.name = 'blackbeard'")
|
1115
|
+
assert_equal authors(:david), authors.first
|
1116
|
+
end
|
1117
|
+
|
1118
|
+
def test_has_many_through_with_primary_key_option
|
1119
|
+
assert_equal [categories(:general)], authors(:david).essay_categories_2
|
1120
|
+
|
1121
|
+
authors = Author.joins(:essay_categories_2).where("categories.id" => categories(:general).id)
|
1122
|
+
assert_equal authors(:david), authors.first
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
def test_size_of_through_association_should_increase_correctly_when_has_many_association_is_added
|
1126
|
+
post = posts(:thinking)
|
1127
|
+
readers = post.readers.size
|
1128
|
+
post.people << people(:michael)
|
1129
|
+
assert_equal readers + 1, post.readers.size
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
def test_has_many_through_with_default_scope_on_join_model
|
1133
|
+
assert_equal posts(:welcome).comments.order("id").to_a, authors(:david).comments_on_first_posts
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
def test_create_has_many_through_with_default_scope_on_join_model
|
1137
|
+
category = authors(:david).special_categories.create(name: "Foo")
|
1138
|
+
assert_equal 1, category.categorizations.where(special: true).count
|
1139
|
+
end
|
1140
|
+
|
1141
|
+
def test_joining_has_many_through_with_distinct
|
1142
|
+
mary = Author.joins(:unique_categorized_posts).where(id: authors(:mary).id).first
|
1143
|
+
assert_equal 1, mary.unique_categorized_posts.length
|
1144
|
+
assert_equal 1, mary.unique_categorized_post_ids.length
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def test_joining_has_many_through_belongs_to
|
1148
|
+
posts = Post.joins(:author_categorizations).order("posts.id").
|
1149
|
+
where("categorizations.id" => categorizations(:mary_thinking_sti).id)
|
1150
|
+
|
1151
|
+
assert_equal [posts(:eager_other), posts(:misc_by_mary), posts(:other_by_mary)], posts
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
def test_select_chosen_fields_only
|
1155
|
+
author = authors(:david)
|
1156
|
+
assert_equal ["body", "id"].sort, author.comments.select("comments.body").first.attributes.keys.sort
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
def test_get_has_many_through_belongs_to_ids_with_conditions
|
1160
|
+
assert_equal [categories(:general).id], authors(:mary).categories_like_general_ids
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
def test_get_collection_singular_ids_on_has_many_through_with_conditions_and_include
|
1164
|
+
person = Person.first
|
1165
|
+
assert_equal person.posts_with_no_comment_ids, person.posts_with_no_comments.map(&:id)
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
def test_count_has_many_through_with_named_scope
|
1169
|
+
assert_equal 2, authors(:mary).categories.count
|
1170
|
+
assert_equal 1, authors(:mary).categories.general.count
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
def test_has_many_through_belongs_to_should_update_when_the_through_foreign_key_changes
|
1174
|
+
post = posts(:eager_other)
|
1175
|
+
|
1176
|
+
post.author_categorizations
|
1177
|
+
proxy = post.send(:association_instance_get, :author_categorizations)
|
1178
|
+
|
1179
|
+
assert_not_predicate proxy, :stale_target?
|
1180
|
+
assert_equal authors(:mary).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
|
1181
|
+
|
1182
|
+
post.author_id = authors(:david).id
|
1183
|
+
|
1184
|
+
assert_predicate proxy, :stale_target?
|
1185
|
+
assert_equal authors(:david).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
def test_create_with_conditions_hash_on_through_association
|
1189
|
+
member = members(:groucho)
|
1190
|
+
club = member.clubs.create!
|
1191
|
+
|
1192
|
+
assert_equal true, club.reload.membership.favourite
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def test_deleting_from_has_many_through_a_belongs_to_should_not_try_to_update_counter
|
1196
|
+
post = posts(:welcome)
|
1197
|
+
address = author_addresses(:david_address)
|
1198
|
+
|
1199
|
+
assert_includes post.author_addresses, address
|
1200
|
+
post.author_addresses.delete(address)
|
1201
|
+
assert_predicate post[:author_count], :nil?
|
1202
|
+
end
|
1203
|
+
|
1204
|
+
def test_primary_key_option_on_source
|
1205
|
+
post = posts(:welcome)
|
1206
|
+
category = categories(:general)
|
1207
|
+
Categorization.create!(post_id: post.id, named_category_name: category.name)
|
1208
|
+
|
1209
|
+
assert_equal [category], post.named_categories
|
1210
|
+
assert_equal [category.name], post.named_category_ids # checks when target loaded
|
1211
|
+
assert_equal [category.name], post.reload.named_category_ids # checks when target no loaded
|
1212
|
+
end
|
1213
|
+
|
1214
|
+
def test_create_should_not_raise_exception_when_join_record_has_errors
|
1215
|
+
repair_validations(Categorization) do
|
1216
|
+
Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
|
1217
|
+
assert_deprecated { Category.create(name: "Fishing", authors: [Author.first]) }
|
1218
|
+
end
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
def test_assign_array_to_new_record_builds_join_records
|
1222
|
+
c = Category.new(name: "Fishing", authors: [Author.first])
|
1223
|
+
assert_equal 1, c.categorizations.size
|
1224
|
+
end
|
1225
|
+
|
1226
|
+
def test_create_bang_should_raise_exception_when_join_record_has_errors
|
1227
|
+
repair_validations(Categorization) do
|
1228
|
+
Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
|
1229
|
+
assert_raises(ActiveRecord::RecordInvalid) do
|
1230
|
+
assert_deprecated { Category.create!(name: "Fishing", authors: [Author.first]) }
|
1231
|
+
end
|
1232
|
+
end
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
def test_save_bang_should_raise_exception_when_join_record_has_errors
|
1236
|
+
repair_validations(Categorization) do
|
1237
|
+
Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
|
1238
|
+
c = Category.new(name: "Fishing", authors: [Author.first])
|
1239
|
+
assert_raises(ActiveRecord::RecordInvalid) do
|
1240
|
+
assert_deprecated { c.save! }
|
1241
|
+
end
|
1242
|
+
end
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
def test_save_returns_falsy_when_join_record_has_errors
|
1246
|
+
repair_validations(Categorization) do
|
1247
|
+
Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
|
1248
|
+
c = Category.new(name: "Fishing", authors: [Author.first])
|
1249
|
+
assert_deprecated { assert_not c.save }
|
1250
|
+
end
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
def test_preloading_empty_through_association_via_joins
|
1254
|
+
person = Person.create!(first_name: "Gaga")
|
1255
|
+
person = Person.where(id: person.id).where("readers.id = 1 or 1=1").references(:readers).includes(:posts).to_a.first
|
1256
|
+
|
1257
|
+
assert person.posts.loaded?, "person.posts should be loaded"
|
1258
|
+
assert_equal [], person.posts
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
def test_preloading_empty_through_with_polymorphic_source_association
|
1262
|
+
owner = Owner.create!(name: "Rainbow Unicat")
|
1263
|
+
pet = Pet.create!(owner: owner)
|
1264
|
+
person = Person.create!(first_name: "Gaga")
|
1265
|
+
treasure = Treasure.create!(looter: person)
|
1266
|
+
non_looted_treasure = Treasure.create!()
|
1267
|
+
PetTreasure.create!(pet: pet, treasure: treasure, rainbow_color: "Ultra violet indigo")
|
1268
|
+
PetTreasure.create!(pet: pet, treasure: non_looted_treasure, rainbow_color: "Ultra violet indigo")
|
1269
|
+
|
1270
|
+
assert_equal [person], Owner.where(name: "Rainbow Unicat").includes(pets: :persons).first.persons.to_a
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
def test_explicitly_joining_join_table
|
1274
|
+
assert_equal owners(:blackbeard).toys, owners(:blackbeard).toys.with_pet
|
1275
|
+
end
|
1276
|
+
|
1277
|
+
def test_has_many_through_with_polymorphic_source
|
1278
|
+
post = tags(:general).tagged_posts.create! title: "foo", body: "bar"
|
1279
|
+
assert_equal [tags(:general)], post.reload.tags
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
def test_has_many_through_obeys_order_on_through_association
|
1283
|
+
owner = owners(:blackbeard)
|
1284
|
+
assert_includes owner.toys.to_sql, "pets.name desc"
|
1285
|
+
assert_equal ["parrot", "bulbul"], owner.toys.map { |r| r.pet.name }
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
def test_has_many_through_associations_sum_on_columns
|
1289
|
+
post1 = Post.create(title: "active", body: "sample")
|
1290
|
+
post2 = Post.create(title: "inactive", body: "sample")
|
1291
|
+
|
1292
|
+
person1 = Person.create(first_name: "aaron", followers_count: 1)
|
1293
|
+
person2 = Person.create(first_name: "schmit", followers_count: 2)
|
1294
|
+
person3 = Person.create(first_name: "bill", followers_count: 3)
|
1295
|
+
person4 = Person.create(first_name: "cal", followers_count: 4)
|
1296
|
+
|
1297
|
+
Reader.create(post_id: post1.id, person_id: person1.id)
|
1298
|
+
Reader.create(post_id: post1.id, person_id: person2.id)
|
1299
|
+
Reader.create(post_id: post1.id, person_id: person3.id)
|
1300
|
+
Reader.create(post_id: post1.id, person_id: person4.id)
|
1301
|
+
|
1302
|
+
Reader.create(post_id: post2.id, person_id: person1.id)
|
1303
|
+
Reader.create(post_id: post2.id, person_id: person2.id)
|
1304
|
+
Reader.create(post_id: post2.id, person_id: person3.id)
|
1305
|
+
Reader.create(post_id: post2.id, person_id: person4.id)
|
1306
|
+
|
1307
|
+
active_persons = Person.joins(:readers).joins(:posts).distinct(true).where("posts.title" => "active")
|
1308
|
+
|
1309
|
+
assert_equal active_persons.map(&:followers_count).reduce(:+), 10
|
1310
|
+
assert_equal active_persons.sum(:followers_count), 10
|
1311
|
+
assert_equal active_persons.sum(:followers_count), active_persons.map(&:followers_count).reduce(:+)
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
def test_has_many_through_associations_on_new_records_use_null_relations
|
1315
|
+
person = Person.new
|
1316
|
+
|
1317
|
+
assert_no_queries do
|
1318
|
+
assert_equal [], person.posts
|
1319
|
+
assert_equal [], person.posts.where(body: "omg")
|
1320
|
+
assert_equal [], person.posts.pluck(:body)
|
1321
|
+
assert_equal 0, person.posts.sum(:tags_count)
|
1322
|
+
assert_equal 0, person.posts.count
|
1323
|
+
end
|
1324
|
+
end
|
1325
|
+
|
1326
|
+
def test_has_many_through_with_default_scope_on_the_target
|
1327
|
+
person = people(:michael)
|
1328
|
+
assert_equal [posts(:thinking).id], person.first_posts.map(&:id)
|
1329
|
+
|
1330
|
+
readers(:michael_authorless).update(first_post_id: 1)
|
1331
|
+
assert_equal [posts(:thinking).id], person.reload.first_posts.map(&:id)
|
1332
|
+
end
|
1333
|
+
|
1334
|
+
def test_has_many_through_with_includes_in_through_association_scope
|
1335
|
+
assert_not_empty posts(:welcome).author_address_extra_with_address
|
1336
|
+
end
|
1337
|
+
|
1338
|
+
def test_insert_records_via_has_many_through_association_with_scope
|
1339
|
+
club = Club.create!
|
1340
|
+
member = Member.create!
|
1341
|
+
Membership.create!(club: club, member: member)
|
1342
|
+
|
1343
|
+
club.favourites << member
|
1344
|
+
assert_equal [member], club.favourites
|
1345
|
+
|
1346
|
+
club.reload
|
1347
|
+
assert_equal [member], club.favourites
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
def test_has_many_through_unscope_default_scope
|
1351
|
+
post = Post.create!(title: "Beaches", body: "I like beaches!")
|
1352
|
+
Reader.create! person: people(:david), post: post
|
1353
|
+
LazyReader.create! person: people(:susan), post: post
|
1354
|
+
|
1355
|
+
assert_equal 2, post.people.to_a.size
|
1356
|
+
assert_equal 1, post.lazy_people.to_a.size
|
1357
|
+
|
1358
|
+
assert_equal 2, post.lazy_readers_unscope_skimmers.to_a.size
|
1359
|
+
assert_equal 2, post.lazy_people_unscope_skimmers.to_a.size
|
1360
|
+
end
|
1361
|
+
|
1362
|
+
def test_has_many_through_add_with_sti_middle_relation
|
1363
|
+
club = SuperClub.create!(name: "Fight Club")
|
1364
|
+
member = Member.create!(name: "Tyler Durden")
|
1365
|
+
|
1366
|
+
club.members << member
|
1367
|
+
assert_equal 1, SuperMembership.where(member_id: member.id, club_id: club.id).count
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
def test_build_for_has_many_through_association
|
1371
|
+
organization = organizations(:nsa)
|
1372
|
+
author = organization.author
|
1373
|
+
post_direct = author.posts.build
|
1374
|
+
post_through = organization.posts.build
|
1375
|
+
assert_equal post_direct.author_id, post_through.author_id
|
1376
|
+
end
|
1377
|
+
|
1378
|
+
def test_has_many_through_with_scope_that_should_not_be_fully_merged
|
1379
|
+
Club.has_many :distinct_memberships, -> { distinct }, class_name: "Membership"
|
1380
|
+
Club.has_many :special_favourites, through: :distinct_memberships, source: :member
|
1381
|
+
|
1382
|
+
assert_nil Club.new.special_favourites.distinct_value
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
def test_has_many_through_do_not_cache_association_reader_if_the_though_method_has_default_scopes
|
1386
|
+
member = Member.create!
|
1387
|
+
club = Club.create!
|
1388
|
+
TenantMembership.create!(
|
1389
|
+
member: member,
|
1390
|
+
club: club
|
1391
|
+
)
|
1392
|
+
|
1393
|
+
TenantMembership.current_member = member
|
1394
|
+
|
1395
|
+
tenant_clubs = member.tenant_clubs
|
1396
|
+
assert_equal [club], tenant_clubs
|
1397
|
+
|
1398
|
+
TenantMembership.current_member = nil
|
1399
|
+
|
1400
|
+
other_member = Member.create!
|
1401
|
+
other_club = Club.create!
|
1402
|
+
TenantMembership.create!(
|
1403
|
+
member: other_member,
|
1404
|
+
club: other_club
|
1405
|
+
)
|
1406
|
+
|
1407
|
+
tenant_clubs = other_member.tenant_clubs
|
1408
|
+
assert_equal [other_club], tenant_clubs
|
1409
|
+
ensure
|
1410
|
+
TenantMembership.current_member = nil
|
1411
|
+
end
|
1412
|
+
|
1413
|
+
def test_has_many_through_with_scope_that_has_joined_same_table_with_parent_relation
|
1414
|
+
assert_equal authors(:david), Author.joins(:comments_for_first_author).take
|
1415
|
+
end
|
1416
|
+
|
1417
|
+
def test_has_many_through_with_left_joined_same_table_with_through_table
|
1418
|
+
assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.left_joins(:post)
|
1419
|
+
end
|
1420
|
+
|
1421
|
+
def test_has_many_through_with_unscope_should_affect_to_through_scope
|
1422
|
+
assert_equal [comments(:eager_other_comment1)], authors(:mary).unordered_comments
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
def test_has_many_through_with_scope_should_accept_string_and_hash_join
|
1426
|
+
assert_equal authors(:david), Author.joins({ comments_for_first_author: :post }, "inner join posts posts_alias on authors.id = posts_alias.author_id").eager_load(:categories).take
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
def test_has_many_through_with_scope_should_respect_table_alias
|
1430
|
+
family = Family.create!
|
1431
|
+
users = 3.times.map { User.create! }
|
1432
|
+
FamilyTree.create!(member: users[0], family: family)
|
1433
|
+
FamilyTree.create!(member: users[1], family: family)
|
1434
|
+
FamilyTree.create!(member: users[2], family: family, token: "wat")
|
1435
|
+
|
1436
|
+
assert_equal 2, users[0].family_members.to_a.size
|
1437
|
+
assert_equal 0, users[2].family_members.to_a.size
|
1438
|
+
end
|
1439
|
+
|
1440
|
+
def test_through_scope_is_affected_by_unscoping
|
1441
|
+
author = authors(:david)
|
1442
|
+
|
1443
|
+
expected = author.comments.to_a
|
1444
|
+
FirstPost.unscoped do
|
1445
|
+
assert_equal expected.sort_by(&:id), author.comments_on_first_posts.sort_by(&:id)
|
1446
|
+
end
|
1447
|
+
end
|
1448
|
+
|
1449
|
+
def test_through_scope_isnt_affected_by_scoping
|
1450
|
+
author = authors(:david)
|
1451
|
+
|
1452
|
+
expected = author.comments_on_first_posts.to_a
|
1453
|
+
FirstPost.where(id: 2).scoping do
|
1454
|
+
author.comments_on_first_posts.reset
|
1455
|
+
assert_equal expected.sort_by(&:id), author.comments_on_first_posts.sort_by(&:id)
|
1456
|
+
end
|
1457
|
+
end
|
1458
|
+
|
1459
|
+
def test_incorrectly_ordered_through_associations
|
1460
|
+
assert_raises(ActiveRecord::HasManyThroughOrderError) do
|
1461
|
+
DeveloperWithIncorrectlyOrderedHasManyThrough.create(
|
1462
|
+
companies: [Company.create]
|
1463
|
+
)
|
1464
|
+
end
|
1465
|
+
end
|
1466
|
+
|
1467
|
+
def test_has_many_through_update_ids_with_conditions
|
1468
|
+
author = Author.create!(name: "Bill")
|
1469
|
+
category = categories(:general)
|
1470
|
+
|
1471
|
+
author.update(
|
1472
|
+
special_categories_with_condition_ids: [category.id],
|
1473
|
+
nonspecial_categories_with_condition_ids: [category.id]
|
1474
|
+
)
|
1475
|
+
|
1476
|
+
assert_equal [category.id], author.special_categories_with_condition_ids
|
1477
|
+
assert_equal [category.id], author.nonspecial_categories_with_condition_ids
|
1478
|
+
|
1479
|
+
author.update(nonspecial_categories_with_condition_ids: [])
|
1480
|
+
author.reload
|
1481
|
+
|
1482
|
+
assert_equal [category.id], author.special_categories_with_condition_ids
|
1483
|
+
assert_equal [], author.nonspecial_categories_with_condition_ids
|
1484
|
+
end
|
1485
|
+
|
1486
|
+
def test_single_has_many_through_association_with_unpersisted_parent_instance
|
1487
|
+
post_with_single_has_many_through = Class.new(Post) do
|
1488
|
+
def self.name; "PostWithSingleHasManyThrough"; end
|
1489
|
+
has_many :subscriptions, through: :author
|
1490
|
+
end
|
1491
|
+
post = post_with_single_has_many_through.new
|
1492
|
+
|
1493
|
+
post.author = authors(:mary)
|
1494
|
+
book1 = Book.create!(name: "essays on single has many through associations 1")
|
1495
|
+
post.author.books << book1
|
1496
|
+
subscription1 = Subscription.first
|
1497
|
+
book1.subscriptions << subscription1
|
1498
|
+
assert_equal [subscription1], post.subscriptions.to_a
|
1499
|
+
|
1500
|
+
post.author = authors(:bob)
|
1501
|
+
book2 = Book.create!(name: "essays on single has many through associations 2")
|
1502
|
+
post.author.books << book2
|
1503
|
+
subscription2 = Subscription.second
|
1504
|
+
book2.subscriptions << subscription2
|
1505
|
+
assert_equal [subscription2], post.subscriptions.to_a
|
1506
|
+
end
|
1507
|
+
|
1508
|
+
def test_nested_has_many_through_association_with_unpersisted_parent_instance
|
1509
|
+
post_with_nested_has_many_through = Class.new(Post) do
|
1510
|
+
def self.name; "PostWithNestedHasManyThrough"; end
|
1511
|
+
has_many :books, through: :author
|
1512
|
+
has_many :subscriptions, through: :books
|
1513
|
+
end
|
1514
|
+
post = post_with_nested_has_many_through.new
|
1515
|
+
|
1516
|
+
post.author = authors(:mary)
|
1517
|
+
book1 = Book.create!(name: "essays on nested has many through associations 1")
|
1518
|
+
post.author.books << book1
|
1519
|
+
subscription1 = Subscription.first
|
1520
|
+
book1.subscriptions << subscription1
|
1521
|
+
assert_equal [subscription1], post.subscriptions.to_a
|
1522
|
+
|
1523
|
+
post.author = authors(:bob)
|
1524
|
+
book2 = Book.create!(name: "essays on nested has many through associations 2")
|
1525
|
+
post.author.books << book2
|
1526
|
+
subscription2 = Subscription.second
|
1527
|
+
book2.subscriptions << subscription2
|
1528
|
+
assert_equal [subscription2], post.subscriptions.to_a
|
1529
|
+
end
|
1530
|
+
|
1531
|
+
def test_child_is_visible_to_join_model_in_add_association_callbacks
|
1532
|
+
[:before_add, :after_add].each do |callback_name|
|
1533
|
+
sentient_treasure = Class.new(Treasure) do
|
1534
|
+
def self.name; "SentientTreasure"; end
|
1535
|
+
|
1536
|
+
has_many :pet_treasures, foreign_key: :treasure_id, callback_name => :check_pet!
|
1537
|
+
has_many :pets, through: :pet_treasures
|
1538
|
+
|
1539
|
+
def check_pet!(added)
|
1540
|
+
raise "No pet!" if added.pet.nil?
|
1541
|
+
end
|
1542
|
+
end
|
1543
|
+
|
1544
|
+
treasure = sentient_treasure.new
|
1545
|
+
assert_nothing_raised { treasure.pets << pets(:mochi) }
|
1546
|
+
end
|
1547
|
+
end
|
1548
|
+
|
1549
|
+
def test_circular_autosave_association_correctly_saves_multiple_records
|
1550
|
+
cs180 = Seminar.new(name: "CS180")
|
1551
|
+
fall = Session.new(name: "Fall")
|
1552
|
+
sections = [
|
1553
|
+
cs180.sections.build(short_name: "A"),
|
1554
|
+
cs180.sections.build(short_name: "B"),
|
1555
|
+
]
|
1556
|
+
fall.sections << sections
|
1557
|
+
fall.save!
|
1558
|
+
fall.reload
|
1559
|
+
assert_equal sections, fall.sections.sort_by(&:id)
|
1560
|
+
end
|
1561
|
+
|
1562
|
+
private
|
1563
|
+
def make_model(name)
|
1564
|
+
Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
|
1565
|
+
end
|
1566
|
+
|
1567
|
+
def make_no_pk_hm_t
|
1568
|
+
lesson = make_model "Lesson"
|
1569
|
+
student = make_model "Student"
|
1570
|
+
|
1571
|
+
lesson_student = make_model "LessonStudent"
|
1572
|
+
lesson_student.table_name = "lessons_students"
|
1573
|
+
|
1574
|
+
lesson_student.belongs_to :lesson, anonymous_class: lesson
|
1575
|
+
lesson_student.belongs_to :student, anonymous_class: student
|
1576
|
+
lesson.has_many :lesson_students, anonymous_class: lesson_student
|
1577
|
+
lesson.has_many :students, through: :lesson_students, anonymous_class: student
|
1578
|
+
[lesson, lesson_student, student]
|
1579
|
+
end
|
1580
|
+
end
|