ibm_db 3.0.0-x86-mingw32 → 3.0.1-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES +4 -0
- data/MANIFEST +14 -14
- data/README +225 -225
- data/ext/Makefile.nt32 +181 -181
- data/ext/Makefile.nt32.191 +212 -212
- data/ext/OLD/extconf.rb +264 -0
- data/ext/{extconf_MacOS.rb → OLD/extconf_MacOS.rb} +269 -269
- data/ext/extconf.rb +291 -264
- data/ext/ibm_db.c +2 -2
- data/ext/ruby_ibm_db.h +241 -241
- data/ext/ruby_ibm_db_cli.h +500 -500
- data/init.rb +41 -41
- data/lib/IBM_DB.rb +27 -27
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +4 -4
- data/lib/active_record/connection_adapters/ibmdb_adapter.rb +1 -1
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
- data/lib/mswin32/ibm_db.rb +115 -115
- data/test/active_record/connection_adapters/fake_adapter.rb +46 -0
- data/test/assets/example.log +1 -0
- data/test/assets/flowers.jpg +0 -0
- data/test/assets/test.txt +1 -0
- data/test/cases/adapter_test.rb +261 -207
- data/test/cases/aggregations_test.rb +158 -0
- data/test/cases/ar_schema_test.rb +161 -0
- data/test/cases/associations/association_scope_test.rb +21 -0
- data/test/cases/associations/belongs_to_associations_test.rb +1029 -711
- data/test/cases/associations/callbacks_test.rb +192 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +188 -181
- data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +26 -0
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
- data/test/cases/associations/eager_load_nested_include_test.rb +128 -0
- data/test/cases/associations/eager_singularization_test.rb +148 -0
- data/test/cases/associations/eager_test.rb +1411 -0
- data/test/cases/associations/extension_test.rb +82 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +932 -851
- data/test/cases/associations/has_many_associations_test.rb +2162 -0
- data/test/cases/associations/has_many_through_associations_test.rb +1204 -0
- data/test/cases/associations/has_one_associations_test.rb +610 -0
- data/test/cases/associations/has_one_through_associations_test.rb +380 -0
- data/test/cases/associations/inner_join_association_test.rb +139 -0
- data/test/cases/associations/inverse_associations_test.rb +693 -0
- data/test/cases/associations/join_model_test.rb +754 -743
- data/test/cases/associations/nested_through_associations_test.rb +579 -0
- data/test/cases/associations/required_test.rb +82 -0
- data/test/cases/associations_test.rb +380 -0
- data/test/cases/attribute_decorators_test.rb +125 -0
- data/test/cases/attribute_methods/read_test.rb +60 -0
- data/test/cases/attribute_methods/serialization_test.rb +29 -0
- data/test/cases/attribute_methods_test.rb +952 -822
- data/test/cases/attribute_set_test.rb +200 -0
- data/test/cases/attribute_test.rb +180 -0
- data/test/cases/attributes_test.rb +136 -0
- data/test/cases/autosave_association_test.rb +1595 -0
- data/test/cases/base_test.rb +1638 -2133
- data/test/cases/batches_test.rb +212 -0
- data/test/cases/binary_test.rb +52 -0
- data/test/cases/bind_parameter_test.rb +100 -0
- data/test/cases/calculations_test.rb +646 -482
- data/test/cases/callbacks_test.rb +543 -0
- data/test/cases/clone_test.rb +40 -0
- data/test/cases/coders/yaml_column_test.rb +63 -0
- data/test/cases/column_alias_test.rb +17 -0
- data/test/cases/column_definition_test.rb +123 -0
- data/test/cases/connection_adapters/adapter_leasing_test.rb +54 -0
- data/test/cases/connection_adapters/connection_handler_test.rb +53 -0
- data/test/cases/connection_adapters/connection_specification_test.rb +12 -0
- data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +293 -0
- data/test/cases/connection_adapters/mysql_type_lookup_test.rb +65 -0
- data/test/cases/connection_adapters/quoting_test.rb +13 -0
- data/test/cases/connection_adapters/schema_cache_test.rb +56 -0
- data/test/cases/connection_adapters/type_lookup_test.rb +110 -0
- data/test/cases/connection_management_test.rb +122 -0
- data/test/cases/connection_pool_test.rb +346 -0
- data/test/cases/connection_specification/resolver_test.rb +116 -0
- data/test/cases/core_test.rb +112 -0
- data/test/cases/counter_cache_test.rb +209 -0
- data/test/cases/custom_locking_test.rb +17 -0
- data/test/cases/database_statements_test.rb +19 -0
- data/test/cases/date_time_test.rb +61 -0
- data/test/cases/defaults_test.rb +223 -0
- data/test/cases/dirty_test.rb +775 -0
- data/test/cases/disconnected_test.rb +28 -0
- data/test/cases/dup_test.rb +157 -0
- data/test/cases/enum_test.rb +290 -0
- data/test/cases/explain_subscriber_test.rb +64 -0
- data/test/cases/explain_test.rb +76 -0
- data/test/cases/finder_respond_to_test.rb +60 -0
- data/test/cases/finder_test.rb +1166 -0
- data/test/cases/fixture_set/file_test.rb +138 -0
- data/test/cases/fixtures_test.rb +897 -0
- data/test/cases/forbidden_attributes_protection_test.rb +99 -0
- data/test/cases/habtm_destroy_order_test.rb +61 -0
- data/test/cases/helper.rb +210 -0
- data/test/cases/hot_compatibility_test.rb +54 -0
- data/test/cases/i18n_test.rb +45 -0
- data/test/cases/inheritance_test.rb +375 -0
- data/test/cases/integration_test.rb +139 -0
- data/test/cases/invalid_connection_test.rb +22 -0
- data/test/cases/invalid_date_test.rb +32 -0
- data/test/cases/invertible_migration_test.rb +295 -0
- data/test/cases/json_serialization_test.rb +302 -0
- data/test/cases/locking_test.rb +477 -0
- data/test/cases/log_subscriber_test.rb +136 -0
- data/test/cases/migration/change_schema_test - Copy.rb +448 -0
- data/test/cases/migration/change_schema_test.rb +472 -0
- data/test/cases/migration/change_table_test.rb +224 -0
- data/test/cases/migration/column_attributes_test.rb +192 -0
- data/test/cases/migration/column_positioning_test.rb +56 -0
- data/test/cases/migration/columns_test.rb +304 -0
- data/test/cases/migration/command_recorder_test.rb +305 -0
- data/test/cases/migration/create_join_table_test.rb +148 -0
- data/test/cases/migration/foreign_key_test - Changed.rb +325 -0
- data/test/cases/migration/foreign_key_test.rb +360 -0
- data/test/cases/migration/helper.rb +39 -0
- data/test/cases/migration/index_test.rb +216 -0
- data/test/cases/migration/logger_test.rb +36 -0
- data/test/cases/migration/pending_migrations_test.rb +53 -0
- data/test/cases/migration/references_foreign_key_test.rb +214 -0
- data/test/cases/migration/references_index_test.rb +101 -0
- data/test/cases/migration/references_statements_test.rb +116 -0
- data/test/cases/migration/rename_table_test.rb +93 -0
- data/test/cases/migration/table_and_index_test.rb +24 -0
- data/test/cases/migration_test.rb +959 -2408
- data/test/cases/migrator_test.rb +388 -0
- data/test/cases/mixin_test.rb +70 -0
- data/test/cases/modules_test.rb +173 -0
- data/test/cases/multiparameter_attributes_test.rb +350 -0
- data/test/cases/multiple_db_test.rb +115 -0
- data/test/cases/nested_attributes_test.rb +1057 -0
- data/test/cases/nested_attributes_with_callbacks_test.rb +144 -0
- data/test/cases/persistence_test.rb +909 -642
- data/test/cases/pooled_connections_test.rb +81 -0
- data/test/cases/primary_keys_test.rb +237 -0
- data/test/cases/query_cache_test.rb +326 -257
- data/test/cases/quoting_test.rb +156 -0
- data/test/cases/readonly_test.rb +118 -0
- data/test/cases/reaper_test.rb +85 -0
- data/test/cases/reflection_test.rb +454 -0
- data/test/cases/relation/delegation_test.rb +68 -0
- data/test/cases/relation/merging_test.rb +161 -0
- data/test/cases/relation/mutation_test.rb +165 -0
- data/test/cases/relation/predicate_builder_test.rb +14 -0
- data/test/cases/relation/where_chain_test.rb +181 -0
- data/test/cases/relation/where_test.rb +300 -0
- data/test/cases/relation/where_test2.rb +36 -0
- data/test/cases/relation_test.rb +297 -0
- data/test/cases/relations_test.rb +1815 -1182
- data/test/cases/reload_models_test.rb +22 -0
- data/test/cases/result_test.rb +80 -0
- data/test/cases/sanitize_test.rb +83 -0
- data/test/cases/schema_dumper_test.rb +463 -256
- data/test/cases/scoping/default_scoping_test.rb +454 -0
- data/test/cases/scoping/named_scoping_test.rb +524 -0
- data/test/cases/scoping/relation_scoping_test.rb +357 -0
- data/test/cases/serialization_test.rb +104 -0
- data/test/cases/serialized_attribute_test.rb +277 -0
- data/test/cases/statement_cache_test.rb +98 -0
- data/test/cases/store_test.rb +194 -0
- data/test/cases/tasks/database_tasks_test.rb +396 -0
- data/test/cases/tasks/mysql_rake_test.rb +311 -0
- data/test/cases/tasks/postgresql_rake_test.rb +245 -0
- data/test/cases/tasks/sqlite_rake_test.rb +193 -0
- data/test/cases/test_case.rb +123 -0
- data/test/cases/timestamp_test.rb +468 -0
- data/test/cases/transaction_callbacks_test.rb +452 -300
- data/test/cases/transaction_isolation_test.rb +106 -0
- data/test/cases/transactions_test.rb +817 -0
- data/test/cases/type/decimal_test.rb +51 -0
- data/test/cases/type/integer_test.rb +121 -0
- data/test/cases/type/string_test.rb +36 -0
- data/test/cases/type/type_map_test.rb +177 -0
- data/test/cases/type/unsigned_integer_test.rb +18 -0
- data/test/cases/types_test.rb +141 -0
- data/test/cases/unconnected_test.rb +33 -0
- data/test/cases/validations/association_validation_test.rb +86 -0
- data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -0
- data/test/cases/validations/i18n_validation_test.rb +90 -0
- data/test/cases/validations/length_validation_test.rb +47 -0
- data/test/cases/validations/presence_validation_test.rb +68 -0
- data/test/cases/validations/uniqueness_validation_test.rb +434 -299
- data/test/cases/validations_repair_helper.rb +23 -0
- data/test/cases/validations_test.rb +165 -0
- data/test/cases/view_test.rb +113 -0
- data/test/cases/xml_serialization_test.rb +457 -408
- data/test/cases/yaml_serialization_test.rb +86 -0
- data/test/config.rb +5 -0
- data/test/config.yml +154 -154
- data/test/connections/native_ibm_db/connection.rb +43 -43
- 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/people.yml +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author_addresses.yml +18 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +23 -0
- data/test/fixtures/binaries.yml +133 -0
- data/test/fixtures/books.yml +11 -0
- data/test/fixtures/bulbs.yml +5 -0
- data/test/fixtures/cars.yml +9 -0
- data/test/fixtures/categories.yml +19 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +31 -0
- data/test/fixtures/categorizations.yml +23 -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 +65 -0
- data/test/fixtures/companies.yml +67 -0
- data/test/fixtures/computers.yml +10 -0
- data/test/fixtures/courses.yml +8 -0
- data/test/fixtures/customers.yml +26 -0
- data/test/fixtures/dashboards.yml +6 -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 +6 -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/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/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 +34 -0
- data/test/fixtures/men.yml +5 -0
- data/test/fixtures/minimalistics.yml +2 -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/csv/accounts.csv +1 -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/organizations.yml +5 -0
- data/test/fixtures/other_topics.yml +42 -0
- data/test/fixtures/owners.yml +9 -0
- data/test/fixtures/parrots.yml +27 -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 +12 -0
- data/test/fixtures/posts.yml +80 -0
- data/test/fixtures/price_estimates.yml +7 -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 +11 -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 +12 -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/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/zines.yml +5 -0
- data/test/ibm_db_test.rb +24 -24
- data/test/migrations/10_urban/9_add_expressions.rb +11 -0
- data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
- data/test/migrations/magic/1_currencies_have_symbols.rb +12 -0
- data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
- data/test/migrations/missing/1_people_have_last_names.rb +9 -0
- data/test/migrations/missing/3_we_need_reminders.rb +12 -0
- data/test/migrations/missing/4_innocent_jointable.rb +12 -0
- data/test/migrations/rename/1_we_need_things.rb +11 -0
- data/test/migrations/rename/2_rename_things.rb +9 -0
- data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -0
- data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -0
- data/test/migrations/to_copy2/1_create_articles.rb +7 -0
- data/test/migrations/to_copy2/2_create_comments.rb +7 -0
- data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -0
- data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -0
- data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -0
- data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -0
- data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -0
- data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -0
- data/test/migrations/valid/2_we_need_reminders.rb +12 -0
- data/test/migrations/valid/3_innocent_jointable.rb +12 -0
- data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -0
- data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -0
- data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -0
- data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -0
- data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -0
- data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -0
- data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -0
- data/test/models/admin.rb +5 -0
- data/test/models/admin/account.rb +3 -0
- data/test/models/admin/randomly_named_c1.rb +3 -0
- data/test/models/admin/user.rb +40 -0
- data/test/models/aircraft.rb +4 -0
- data/test/models/arunit2_model.rb +3 -0
- data/test/models/author.rb +212 -0
- data/test/models/auto_id.rb +4 -0
- data/test/models/autoloadable/extra_firm.rb +2 -0
- data/test/models/binary.rb +2 -0
- data/test/models/bird.rb +12 -0
- data/test/models/book.rb +18 -0
- data/test/models/boolean.rb +2 -0
- data/test/models/bulb.rb +51 -0
- data/test/models/cake_designer.rb +3 -0
- data/test/models/car.rb +26 -0
- data/test/models/carrier.rb +2 -0
- data/test/models/categorization.rb +19 -0
- data/test/models/category.rb +35 -0
- data/test/models/chef.rb +3 -0
- data/test/models/citation.rb +3 -0
- data/test/models/club.rb +23 -0
- data/test/models/college.rb +10 -0
- data/test/models/column.rb +3 -0
- data/test/models/column_name.rb +3 -0
- data/test/models/comment.rb +64 -0
- data/test/models/company.rb +225 -0
- data/test/models/company_in_module.rb +98 -0
- data/test/models/computer.rb +3 -0
- data/test/models/contact.rb +41 -0
- data/test/models/contract.rb +20 -0
- data/test/models/country.rb +7 -0
- data/test/models/course.rb +6 -0
- data/test/models/customer.rb +77 -0
- data/test/models/customer_carrier.rb +14 -0
- data/test/models/dashboard.rb +3 -0
- data/test/models/default.rb +2 -0
- data/test/models/department.rb +4 -0
- data/test/models/developer.rb +252 -0
- data/test/models/dog.rb +5 -0
- data/test/models/dog_lover.rb +5 -0
- data/test/models/doubloon.rb +12 -0
- data/test/models/drink_designer.rb +3 -0
- data/test/models/edge.rb +5 -0
- data/test/models/electron.rb +5 -0
- data/test/models/engine.rb +4 -0
- data/test/models/entrant.rb +3 -0
- data/test/models/essay.rb +5 -0
- data/test/models/event.rb +3 -0
- data/test/models/eye.rb +37 -0
- data/test/models/face.rb +9 -0
- data/test/models/friendship.rb +6 -0
- data/test/models/guid.rb +2 -0
- data/test/models/hotel.rb +6 -0
- data/test/models/image.rb +3 -0
- data/test/models/interest.rb +5 -0
- data/test/models/invoice.rb +4 -0
- data/test/models/item.rb +7 -0
- data/test/models/job.rb +7 -0
- data/test/models/joke.rb +7 -0
- data/test/models/keyboard.rb +3 -0
- data/test/models/legacy_thing.rb +3 -0
- data/test/models/lesson.rb +11 -0
- data/test/models/line_item.rb +3 -0
- data/test/models/liquid.rb +4 -0
- data/test/models/man.rb +11 -0
- data/test/models/matey.rb +4 -0
- data/test/models/member.rb +41 -0
- data/test/models/member_detail.rb +7 -0
- data/test/models/member_type.rb +3 -0
- data/test/models/membership.rb +35 -0
- data/test/models/minimalistic.rb +2 -0
- data/test/models/minivan.rb +9 -0
- data/test/models/mixed_case_monkey.rb +3 -0
- data/test/models/molecule.rb +6 -0
- data/test/models/movie.rb +5 -0
- data/test/models/order.rb +4 -0
- data/test/models/organization.rb +14 -0
- data/test/models/owner.rb +34 -0
- data/test/models/parrot.rb +29 -0
- data/test/models/person.rb +143 -0
- data/test/models/personal_legacy_thing.rb +4 -0
- data/test/models/pet.rb +15 -0
- data/test/models/pirate.rb +92 -0
- data/test/models/possession.rb +3 -0
- data/test/models/post.rb +264 -0
- data/test/models/price_estimate.rb +4 -0
- data/test/models/professor.rb +5 -0
- data/test/models/project.rb +29 -0
- data/test/models/publisher.rb +2 -0
- data/test/models/publisher/article.rb +4 -0
- data/test/models/publisher/magazine.rb +3 -0
- data/test/models/randomly_named_c1.rb +3 -0
- data/test/models/rating.rb +4 -0
- data/test/models/reader.rb +23 -0
- data/test/models/record.rb +2 -0
- data/test/models/reference.rb +22 -0
- data/test/models/reply.rb +61 -0
- data/test/models/ship.rb +33 -0
- data/test/models/ship_part.rb +8 -0
- data/test/models/shop.rb +17 -0
- data/test/models/shop_account.rb +6 -0
- data/test/models/speedometer.rb +6 -0
- data/test/models/sponsor.rb +7 -0
- data/test/models/string_key_object.rb +3 -0
- data/test/models/student.rb +4 -0
- data/test/models/subject.rb +16 -0
- data/test/models/subscriber.rb +8 -0
- data/test/models/subscription.rb +4 -0
- data/test/models/tag.rb +7 -0
- data/test/models/tagging.rb +13 -0
- data/test/models/task.rb +5 -0
- data/test/models/topic.rb +124 -0
- data/test/models/toy.rb +6 -0
- data/test/models/traffic_light.rb +4 -0
- data/test/models/treasure.rb +14 -0
- data/test/models/treaty.rb +7 -0
- data/test/models/tyre.rb +11 -0
- data/test/models/uuid_child.rb +3 -0
- data/test/models/uuid_parent.rb +3 -0
- data/test/models/vegetables.rb +24 -0
- data/test/models/vehicle.rb +7 -0
- data/test/models/vertex.rb +9 -0
- data/test/models/warehouse_thing.rb +5 -5
- data/test/models/wheel.rb +3 -0
- data/test/models/without_table.rb +3 -0
- data/test/models/zine.rb +3 -0
- data/test/schema/mysql2_specific_schema.rb +58 -0
- data/test/schema/mysql_specific_schema.rb +70 -0
- data/test/schema/oracle_specific_schema.rb +43 -0
- data/test/schema/postgresql_specific_schema.rb +202 -0
- data/test/schema/schema.rb +938 -751
- data/test/schema/sqlite_specific_schema.rb +22 -0
- data/test/support/config.rb +43 -0
- data/test/support/connection.rb +22 -0
- data/test/support/connection_helper.rb +14 -0
- data/test/support/ddl_helper.rb +8 -0
- data/test/support/schema_dumping_helper.rb +20 -0
- metadata +444 -18
@@ -0,0 +1,1204 @@
|
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/post'
|
3
|
+
require 'models/person'
|
4
|
+
require 'models/reference'
|
5
|
+
require 'models/job'
|
6
|
+
require 'models/reader'
|
7
|
+
require 'models/comment'
|
8
|
+
require 'models/rating'
|
9
|
+
require 'models/tag'
|
10
|
+
require 'models/tagging'
|
11
|
+
require 'models/author'
|
12
|
+
require 'models/owner'
|
13
|
+
require 'models/pet'
|
14
|
+
require 'models/toy'
|
15
|
+
require 'models/contract'
|
16
|
+
require 'models/company'
|
17
|
+
require 'models/developer'
|
18
|
+
require 'models/computer'
|
19
|
+
require 'models/subscriber'
|
20
|
+
require 'models/book'
|
21
|
+
require 'models/subscription'
|
22
|
+
require 'models/essay'
|
23
|
+
require 'models/category'
|
24
|
+
require 'models/categorization'
|
25
|
+
require 'models/member'
|
26
|
+
require 'models/membership'
|
27
|
+
require 'models/club'
|
28
|
+
require 'models/organization'
|
29
|
+
|
30
|
+
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
31
|
+
fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
|
32
|
+
:owners, :pets, :toys, :jobs, :references, :companies, :members, :author_addresses,
|
33
|
+
:subscribers, :books, :subscriptions, :developers, :categorizations, :essays,
|
34
|
+
:categories_posts, :clubs, :memberships, :organizations
|
35
|
+
|
36
|
+
# Dummies to force column loads so query counts are clean.
|
37
|
+
def setup
|
38
|
+
Person.create :first_name => 'gummy'
|
39
|
+
Reader.create :person_id => 0, :post_id => 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_preload_sti_rhs_class
|
43
|
+
developers = Developer.includes(:firms).all.to_a
|
44
|
+
assert_no_queries do
|
45
|
+
developers.each { |d| d.firms }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_preload_sti_middle_relation
|
50
|
+
club = Club.create!(name: 'Aaron cool banana club')
|
51
|
+
member1 = Member.create!(name: 'Aaron')
|
52
|
+
member2 = Member.create!(name: 'Cat')
|
53
|
+
|
54
|
+
SuperMembership.create! club: club, member: member1
|
55
|
+
CurrentMembership.create! club: club, member: member2
|
56
|
+
|
57
|
+
club1 = Club.includes(:members).find_by_id club.id
|
58
|
+
assert_equal [member1, member2].sort_by(&:id),
|
59
|
+
club1.members.sort_by(&:id)
|
60
|
+
end
|
61
|
+
|
62
|
+
def make_model(name)
|
63
|
+
Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_ordered_habtm
|
67
|
+
person_prime = Class.new(ActiveRecord::Base) do
|
68
|
+
def self.name; 'Person'; end
|
69
|
+
|
70
|
+
has_many :readers
|
71
|
+
has_many :posts, -> { order('posts.id DESC') }, :through => :readers
|
72
|
+
end
|
73
|
+
posts = person_prime.includes(:posts).first.posts
|
74
|
+
|
75
|
+
assert_operator posts.length, :>, 1
|
76
|
+
posts.each_cons(2) do |left,right|
|
77
|
+
assert_operator left.id, :>, right.id
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_singleton_has_many_through
|
82
|
+
book = make_model "Book"
|
83
|
+
subscription = make_model "Subscription"
|
84
|
+
subscriber = make_model "Subscriber"
|
85
|
+
|
86
|
+
subscriber.primary_key = 'nick'
|
87
|
+
subscription.belongs_to :book, anonymous_class: book
|
88
|
+
subscription.belongs_to :subscriber, anonymous_class: subscriber
|
89
|
+
|
90
|
+
book.has_many :subscriptions, anonymous_class: subscription
|
91
|
+
book.has_many :subscribers, through: :subscriptions, anonymous_class: subscriber
|
92
|
+
|
93
|
+
anonbook = book.first
|
94
|
+
namebook = Book.find anonbook.id
|
95
|
+
|
96
|
+
assert_operator anonbook.subscribers.count, :>, 0
|
97
|
+
anonbook.subscribers.each do |s|
|
98
|
+
assert_instance_of subscriber, s
|
99
|
+
end
|
100
|
+
assert_equal namebook.subscribers.map(&:id).sort,
|
101
|
+
anonbook.subscribers.map(&:id).sort
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_no_pk_join_table_append
|
105
|
+
lesson, _, student = make_no_pk_hm_t
|
106
|
+
|
107
|
+
sicp = lesson.new(:name => "SICP")
|
108
|
+
ben = student.new(:name => "Ben Bitdiddle")
|
109
|
+
sicp.students << ben
|
110
|
+
assert sicp.save!
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_no_pk_join_table_delete
|
114
|
+
lesson, lesson_student, student = make_no_pk_hm_t
|
115
|
+
|
116
|
+
sicp = lesson.new(:name => "SICP")
|
117
|
+
ben = student.new(:name => "Ben Bitdiddle")
|
118
|
+
louis = student.new(:name => "Louis Reasoner")
|
119
|
+
sicp.students << ben
|
120
|
+
sicp.students << louis
|
121
|
+
assert sicp.save!
|
122
|
+
|
123
|
+
sicp.students.reload
|
124
|
+
assert_operator lesson_student.count, :>=, 2
|
125
|
+
assert_no_difference('student.count') do
|
126
|
+
assert_difference('lesson_student.count', -2) do
|
127
|
+
sicp.students.destroy(*student.all.to_a)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_no_pk_join_model_callbacks
|
133
|
+
lesson, lesson_student, student = make_no_pk_hm_t
|
134
|
+
|
135
|
+
after_destroy_called = false
|
136
|
+
lesson_student.after_destroy do
|
137
|
+
after_destroy_called = true
|
138
|
+
end
|
139
|
+
|
140
|
+
sicp = lesson.new(:name => "SICP")
|
141
|
+
ben = student.new(:name => "Ben Bitdiddle")
|
142
|
+
sicp.students << ben
|
143
|
+
assert sicp.save!
|
144
|
+
|
145
|
+
sicp.students.reload
|
146
|
+
sicp.students.destroy(*student.all.to_a)
|
147
|
+
assert after_destroy_called, "after destroy should be called"
|
148
|
+
end
|
149
|
+
|
150
|
+
def make_no_pk_hm_t
|
151
|
+
lesson = make_model 'Lesson'
|
152
|
+
student = make_model 'Student'
|
153
|
+
|
154
|
+
lesson_student = make_model 'LessonStudent'
|
155
|
+
lesson_student.table_name = 'lessons_students'
|
156
|
+
|
157
|
+
lesson_student.belongs_to :lesson, :anonymous_class => lesson
|
158
|
+
lesson_student.belongs_to :student, :anonymous_class => student
|
159
|
+
lesson.has_many :lesson_students, :anonymous_class => lesson_student
|
160
|
+
lesson.has_many :students, :through => :lesson_students, :anonymous_class => student
|
161
|
+
[lesson, lesson_student, student]
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_pk_is_not_required_for_join
|
165
|
+
post = Post.includes(:scategories).first
|
166
|
+
post2 = Post.includes(:categories).first
|
167
|
+
|
168
|
+
assert_operator post.categories.length, :>, 0
|
169
|
+
assert_equal post2.categories, post.categories
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_include?
|
173
|
+
person = Person.new
|
174
|
+
post = Post.new
|
175
|
+
person.posts << post
|
176
|
+
assert person.posts.include?(post)
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_associate_existing
|
180
|
+
post = posts(:thinking)
|
181
|
+
person = people(:david)
|
182
|
+
|
183
|
+
assert_queries(1) do
|
184
|
+
post.people << person
|
185
|
+
end
|
186
|
+
|
187
|
+
assert_queries(1) do
|
188
|
+
assert post.people.include?(person)
|
189
|
+
end
|
190
|
+
|
191
|
+
assert post.reload.people(true).include?(person)
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_delete_all_for_with_dependent_option_destroy
|
195
|
+
person = people(:david)
|
196
|
+
assert_equal 1, person.jobs_with_dependent_destroy.count
|
197
|
+
|
198
|
+
assert_no_difference 'Job.count' do
|
199
|
+
assert_difference 'Reference.count', -1 do
|
200
|
+
person.reload.jobs_with_dependent_destroy.delete_all
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_delete_all_for_with_dependent_option_nullify
|
206
|
+
person = people(:david)
|
207
|
+
assert_equal 1, person.jobs_with_dependent_nullify.count
|
208
|
+
|
209
|
+
assert_no_difference 'Job.count' do
|
210
|
+
assert_no_difference 'Reference.count' do
|
211
|
+
person.reload.jobs_with_dependent_nullify.delete_all
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_delete_all_for_with_dependent_option_delete_all
|
217
|
+
person = people(:david)
|
218
|
+
assert_equal 1, person.jobs_with_dependent_delete_all.count
|
219
|
+
|
220
|
+
assert_no_difference 'Job.count' do
|
221
|
+
assert_difference 'Reference.count', -1 do
|
222
|
+
person.reload.jobs_with_dependent_delete_all.delete_all
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_concat
|
228
|
+
person = people(:david)
|
229
|
+
post = posts(:thinking)
|
230
|
+
post.people.concat [person]
|
231
|
+
assert_equal 1, post.people.size
|
232
|
+
assert_equal 1, post.people(true).size
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_associate_existing_record_twice_should_add_to_target_twice
|
236
|
+
post = posts(:thinking)
|
237
|
+
person = people(:david)
|
238
|
+
|
239
|
+
assert_difference 'post.people.to_a.count', 2 do
|
240
|
+
post.people << person
|
241
|
+
post.people << person
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_associate_existing_record_twice_should_add_records_twice
|
246
|
+
post = posts(:thinking)
|
247
|
+
person = people(:david)
|
248
|
+
|
249
|
+
assert_difference 'post.people.count', 2 do
|
250
|
+
post.people << person
|
251
|
+
post.people << person
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_add_two_instance_and_then_deleting
|
256
|
+
post = posts(:thinking)
|
257
|
+
person = people(:david)
|
258
|
+
|
259
|
+
post.people << person
|
260
|
+
post.people << person
|
261
|
+
|
262
|
+
counts = ['post.people.count', 'post.people.to_a.count', 'post.readers.count', 'post.readers.to_a.count']
|
263
|
+
assert_difference counts, -2 do
|
264
|
+
post.people.delete(person)
|
265
|
+
end
|
266
|
+
|
267
|
+
assert !post.people.reload.include?(person)
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_associating_new
|
271
|
+
assert_queries(1) { posts(:thinking) }
|
272
|
+
new_person = nil # so block binding catches it
|
273
|
+
|
274
|
+
assert_queries(0) do
|
275
|
+
new_person = Person.new :first_name => 'bob'
|
276
|
+
end
|
277
|
+
|
278
|
+
# Associating new records always saves them
|
279
|
+
# Thus, 1 query for the new person record, 1 query for the new join table record
|
280
|
+
assert_queries(2) do
|
281
|
+
posts(:thinking).people << new_person
|
282
|
+
end
|
283
|
+
|
284
|
+
assert_queries(1) do
|
285
|
+
assert posts(:thinking).people.include?(new_person)
|
286
|
+
end
|
287
|
+
|
288
|
+
assert posts(:thinking).reload.people(true).include?(new_person)
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_associate_new_by_building
|
292
|
+
assert_queries(1) { posts(:thinking) }
|
293
|
+
|
294
|
+
assert_queries(0) do
|
295
|
+
posts(:thinking).people.build(:first_name => "Bob")
|
296
|
+
posts(:thinking).people.new(:first_name => "Ted")
|
297
|
+
end
|
298
|
+
|
299
|
+
# Should only need to load the association once
|
300
|
+
assert_queries(1) do
|
301
|
+
assert posts(:thinking).people.collect(&:first_name).include?("Bob")
|
302
|
+
assert posts(:thinking).people.collect(&:first_name).include?("Ted")
|
303
|
+
end
|
304
|
+
|
305
|
+
# 2 queries for each new record (1 to save the record itself, 1 for the join model)
|
306
|
+
# * 2 new records = 4
|
307
|
+
# + 1 query to save the actual post = 5
|
308
|
+
assert_queries(5) do
|
309
|
+
posts(:thinking).body += '-changed'
|
310
|
+
posts(:thinking).save
|
311
|
+
end
|
312
|
+
|
313
|
+
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Bob")
|
314
|
+
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Ted")
|
315
|
+
end
|
316
|
+
|
317
|
+
def test_build_then_save_with_has_many_inverse
|
318
|
+
post = posts(:thinking)
|
319
|
+
person = post.people.build(:first_name => "Bob")
|
320
|
+
person.save
|
321
|
+
post.reload
|
322
|
+
|
323
|
+
assert post.people.include?(person)
|
324
|
+
end
|
325
|
+
|
326
|
+
def test_build_then_save_with_has_one_inverse
|
327
|
+
post = posts(:thinking)
|
328
|
+
person = post.single_people.build(:first_name => "Bob")
|
329
|
+
person.save
|
330
|
+
post.reload
|
331
|
+
|
332
|
+
assert post.single_people.include?(person)
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_both_parent_ids_set_when_saving_new
|
336
|
+
post = Post.new(title: 'Hello', body: 'world')
|
337
|
+
person = Person.new(first_name: 'Sean')
|
338
|
+
|
339
|
+
post.people = [person]
|
340
|
+
post.save
|
341
|
+
|
342
|
+
assert post.id
|
343
|
+
assert person.id
|
344
|
+
assert_equal post.id, post.readers.first.post_id
|
345
|
+
assert_equal person.id, post.readers.first.person_id
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_delete_association
|
349
|
+
assert_queries(2){posts(:welcome);people(:michael); }
|
350
|
+
|
351
|
+
assert_queries(1) do
|
352
|
+
posts(:welcome).people.delete(people(:michael))
|
353
|
+
end
|
354
|
+
|
355
|
+
assert_queries(1) do
|
356
|
+
assert posts(:welcome).people.empty?
|
357
|
+
end
|
358
|
+
|
359
|
+
assert posts(:welcome).reload.people(true).empty?
|
360
|
+
end
|
361
|
+
|
362
|
+
def test_destroy_association
|
363
|
+
assert_no_difference "Person.count" do
|
364
|
+
assert_difference "Reader.count", -1 do
|
365
|
+
posts(:welcome).people.destroy(people(:michael))
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
assert posts(:welcome).reload.people.empty?
|
370
|
+
assert posts(:welcome).people(true).empty?
|
371
|
+
end
|
372
|
+
|
373
|
+
def test_destroy_all
|
374
|
+
assert_no_difference "Person.count" do
|
375
|
+
assert_difference "Reader.count", -1 do
|
376
|
+
posts(:welcome).people.destroy_all
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
assert posts(:welcome).reload.people.empty?
|
381
|
+
assert posts(:welcome).people(true).empty?
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_should_raise_exception_for_destroying_mismatching_records
|
385
|
+
assert_no_difference ["Person.count", "Reader.count"] do
|
386
|
+
assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:welcome).people.destroy(posts(:thinking)) }
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def test_delete_through_belongs_to_with_dependent_nullify
|
391
|
+
Reference.make_comments = true
|
392
|
+
|
393
|
+
person = people(:michael)
|
394
|
+
job = jobs(:magician)
|
395
|
+
reference = Reference.where(:job_id => job.id, :person_id => person.id).first
|
396
|
+
|
397
|
+
assert_no_difference ['Job.count', 'Reference.count'] do
|
398
|
+
assert_difference 'person.jobs.count', -1 do
|
399
|
+
person.jobs_with_dependent_nullify.delete(job)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
assert_equal nil, reference.reload.job_id
|
404
|
+
ensure
|
405
|
+
Reference.make_comments = false
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_delete_through_belongs_to_with_dependent_delete_all
|
409
|
+
Reference.make_comments = true
|
410
|
+
|
411
|
+
person = people(:michael)
|
412
|
+
job = jobs(:magician)
|
413
|
+
|
414
|
+
# Make sure we're not deleting everything
|
415
|
+
assert person.jobs.count >= 2
|
416
|
+
|
417
|
+
assert_no_difference 'Job.count' do
|
418
|
+
assert_difference ['person.jobs.count', 'Reference.count'], -1 do
|
419
|
+
person.jobs_with_dependent_delete_all.delete(job)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
# Check that the destroy callback on Reference did not run
|
424
|
+
assert_equal nil, person.reload.comments
|
425
|
+
ensure
|
426
|
+
Reference.make_comments = false
|
427
|
+
end
|
428
|
+
|
429
|
+
def test_delete_through_belongs_to_with_dependent_destroy
|
430
|
+
Reference.make_comments = true
|
431
|
+
|
432
|
+
person = people(:michael)
|
433
|
+
job = jobs(:magician)
|
434
|
+
|
435
|
+
# Make sure we're not deleting everything
|
436
|
+
assert person.jobs.count >= 2
|
437
|
+
|
438
|
+
assert_no_difference 'Job.count' do
|
439
|
+
assert_difference ['person.jobs.count', 'Reference.count'], -1 do
|
440
|
+
person.jobs_with_dependent_destroy.delete(job)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
# Check that the destroy callback on Reference ran
|
445
|
+
assert_equal "Reference destroyed", person.reload.comments
|
446
|
+
ensure
|
447
|
+
Reference.make_comments = false
|
448
|
+
end
|
449
|
+
|
450
|
+
def test_belongs_to_with_dependent_destroy
|
451
|
+
person = PersonWithDependentDestroyJobs.find(1)
|
452
|
+
|
453
|
+
# Create a reference which is not linked to a job. This should not be destroyed.
|
454
|
+
person.references.create!
|
455
|
+
|
456
|
+
assert_no_difference 'Job.count' do
|
457
|
+
assert_difference 'Reference.count', -person.jobs.count do
|
458
|
+
person.destroy
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
def test_belongs_to_with_dependent_delete_all
|
464
|
+
person = PersonWithDependentDeleteAllJobs.find(1)
|
465
|
+
|
466
|
+
# Create a reference which is not linked to a job. This should not be destroyed.
|
467
|
+
person.references.create!
|
468
|
+
|
469
|
+
assert_no_difference 'Job.count' do
|
470
|
+
assert_difference 'Reference.count', -person.jobs.count do
|
471
|
+
person.destroy
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_belongs_to_with_dependent_nullify
|
477
|
+
person = PersonWithDependentNullifyJobs.find(1)
|
478
|
+
|
479
|
+
references = person.references.to_a
|
480
|
+
|
481
|
+
assert_no_difference ['Reference.count', 'Job.count'] do
|
482
|
+
person.destroy
|
483
|
+
end
|
484
|
+
|
485
|
+
references.each do |reference|
|
486
|
+
assert_equal nil, reference.reload.job_id
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
def test_update_counter_caches_on_delete
|
491
|
+
post = posts(:welcome)
|
492
|
+
tag = post.tags.create!(:name => 'doomed')
|
493
|
+
|
494
|
+
assert_difference ['post.reload.tags_count'], -1 do
|
495
|
+
posts(:welcome).tags.delete(tag)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def test_update_counter_caches_on_delete_with_dependent_destroy
|
500
|
+
post = posts(:welcome)
|
501
|
+
tag = post.tags.create!(:name => 'doomed')
|
502
|
+
post.update_columns(tags_with_destroy_count: post.tags.count)
|
503
|
+
|
504
|
+
assert_difference ['post.reload.tags_with_destroy_count'], -1 do
|
505
|
+
posts(:welcome).tags_with_destroy.delete(tag)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
def test_update_counter_caches_on_delete_with_dependent_nullify
|
510
|
+
post = posts(:welcome)
|
511
|
+
tag = post.tags.create!(:name => 'doomed')
|
512
|
+
post.update_columns(tags_with_nullify_count: post.tags.count)
|
513
|
+
|
514
|
+
assert_no_difference 'post.reload.tags_count' do
|
515
|
+
assert_difference 'post.reload.tags_with_nullify_count', -1 do
|
516
|
+
posts(:welcome).tags_with_nullify.delete(tag)
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
def test_update_counter_caches_on_replace_association
|
522
|
+
post = posts(:welcome)
|
523
|
+
tag = post.tags.create!(:name => 'doomed')
|
524
|
+
tag.tagged_posts << posts(:thinking)
|
525
|
+
|
526
|
+
tag.tagged_posts = []
|
527
|
+
post.reload
|
528
|
+
|
529
|
+
assert_equal(post.taggings.count, post.tags_count)
|
530
|
+
end
|
531
|
+
|
532
|
+
def test_update_counter_caches_on_destroy
|
533
|
+
post = posts(:welcome)
|
534
|
+
tag = post.tags.create!(name: 'doomed')
|
535
|
+
|
536
|
+
assert_difference 'post.reload.tags_count', -1 do
|
537
|
+
tag.tagged_posts.destroy(post)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
def test_replace_association
|
542
|
+
assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
|
543
|
+
|
544
|
+
# 1 query to delete the existing reader (michael)
|
545
|
+
# 1 query to associate the new reader (david)
|
546
|
+
assert_queries(2) do
|
547
|
+
posts(:welcome).people = [people(:david)]
|
548
|
+
end
|
549
|
+
|
550
|
+
assert_queries(0){
|
551
|
+
assert posts(:welcome).people.include?(people(:david))
|
552
|
+
assert !posts(:welcome).people.include?(people(:michael))
|
553
|
+
}
|
554
|
+
|
555
|
+
assert posts(:welcome).reload.people(true).include?(people(:david))
|
556
|
+
assert !posts(:welcome).reload.people(true).include?(people(:michael))
|
557
|
+
end
|
558
|
+
|
559
|
+
def test_replace_order_is_preserved
|
560
|
+
posts(:welcome).people.clear
|
561
|
+
posts(:welcome).people = [people(:david), people(:michael)]
|
562
|
+
assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id)
|
563
|
+
|
564
|
+
# Test the inverse order in case the first success was a coincidence
|
565
|
+
posts(:welcome).people.clear
|
566
|
+
posts(:welcome).people = [people(:michael), people(:david)]
|
567
|
+
assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id)
|
568
|
+
end
|
569
|
+
|
570
|
+
def test_replace_by_id_order_is_preserved
|
571
|
+
posts(:welcome).people.clear
|
572
|
+
posts(:welcome).person_ids = [people(:david).id, people(:michael).id]
|
573
|
+
assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id)
|
574
|
+
|
575
|
+
# Test the inverse order in case the first success was a coincidence
|
576
|
+
posts(:welcome).people.clear
|
577
|
+
posts(:welcome).person_ids = [people(:michael).id, people(:david).id]
|
578
|
+
assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id)
|
579
|
+
end
|
580
|
+
|
581
|
+
def test_associate_with_create
|
582
|
+
assert_queries(1) { posts(:thinking) }
|
583
|
+
|
584
|
+
# 1 query for the new record, 1 for the join table record
|
585
|
+
# No need to update the actual collection yet!
|
586
|
+
assert_queries(2) do
|
587
|
+
posts(:thinking).people.create(:first_name=>"Jeb")
|
588
|
+
end
|
589
|
+
|
590
|
+
# *Now* we actually need the collection so it's loaded
|
591
|
+
assert_queries(1) do
|
592
|
+
assert posts(:thinking).people.collect(&:first_name).include?("Jeb")
|
593
|
+
end
|
594
|
+
|
595
|
+
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Jeb")
|
596
|
+
end
|
597
|
+
|
598
|
+
def test_through_record_is_built_when_created_with_where
|
599
|
+
assert_difference("posts(:thinking).readers.count", 1) do
|
600
|
+
posts(:thinking).people.where(first_name: "Jeb").create
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
def test_associate_with_create_and_no_options
|
605
|
+
peeps = posts(:thinking).people.count
|
606
|
+
posts(:thinking).people.create(:first_name => 'foo')
|
607
|
+
assert_equal peeps + 1, posts(:thinking).people.count
|
608
|
+
end
|
609
|
+
|
610
|
+
def test_associate_with_create_with_through_having_conditions
|
611
|
+
impatient_people = posts(:thinking).impatient_people.count
|
612
|
+
posts(:thinking).impatient_people.create!(:first_name => 'foo')
|
613
|
+
assert_equal impatient_people + 1, posts(:thinking).impatient_people.count
|
614
|
+
end
|
615
|
+
|
616
|
+
def test_associate_with_create_exclamation_and_no_options
|
617
|
+
peeps = posts(:thinking).people.count
|
618
|
+
posts(:thinking).people.create!(:first_name => 'foo')
|
619
|
+
assert_equal peeps + 1, posts(:thinking).people.count
|
620
|
+
end
|
621
|
+
|
622
|
+
def test_create_on_new_record
|
623
|
+
p = Post.new
|
624
|
+
|
625
|
+
error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create(:first_name => "mew") }
|
626
|
+
assert_equal "You cannot call create unless the parent is saved", error.message
|
627
|
+
|
628
|
+
error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create!(:first_name => "snow") }
|
629
|
+
assert_equal "You cannot call create unless the parent is saved", error.message
|
630
|
+
end
|
631
|
+
|
632
|
+
def test_associate_with_create_and_invalid_options
|
633
|
+
firm = companies(:first_firm)
|
634
|
+
assert_no_difference('firm.developers.count') { assert_nothing_raised { firm.developers.create(:name => '0') } }
|
635
|
+
end
|
636
|
+
|
637
|
+
def test_associate_with_create_and_valid_options
|
638
|
+
firm = companies(:first_firm)
|
639
|
+
assert_difference('firm.developers.count', 1) { firm.developers.create(:name => 'developer') }
|
640
|
+
end
|
641
|
+
|
642
|
+
def test_associate_with_create_bang_and_invalid_options
|
643
|
+
firm = companies(:first_firm)
|
644
|
+
assert_no_difference('firm.developers.count') { assert_raises(ActiveRecord::RecordInvalid) { firm.developers.create!(:name => '0') } }
|
645
|
+
end
|
646
|
+
|
647
|
+
def test_associate_with_create_bang_and_valid_options
|
648
|
+
firm = companies(:first_firm)
|
649
|
+
assert_difference('firm.developers.count', 1) { firm.developers.create!(:name => 'developer') }
|
650
|
+
end
|
651
|
+
|
652
|
+
def test_push_with_invalid_record
|
653
|
+
firm = companies(:first_firm)
|
654
|
+
assert_raises(ActiveRecord::RecordInvalid) { firm.developers << Developer.new(:name => '0') }
|
655
|
+
end
|
656
|
+
|
657
|
+
def test_push_with_invalid_join_record
|
658
|
+
repair_validations(Contract) do
|
659
|
+
Contract.validate {|r| r.errors[:base] << 'Invalid Contract' }
|
660
|
+
|
661
|
+
firm = companies(:first_firm)
|
662
|
+
lifo = Developer.new(:name => 'lifo')
|
663
|
+
assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo }
|
664
|
+
|
665
|
+
lifo = Developer.create!(:name => 'lifo')
|
666
|
+
assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo }
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
def test_clear_associations
|
671
|
+
assert_queries(2) { posts(:welcome);posts(:welcome).people(true) }
|
672
|
+
|
673
|
+
assert_queries(1) do
|
674
|
+
posts(:welcome).people.clear
|
675
|
+
end
|
676
|
+
|
677
|
+
assert_queries(0) do
|
678
|
+
assert posts(:welcome).people.empty?
|
679
|
+
end
|
680
|
+
|
681
|
+
assert posts(:welcome).reload.people(true).empty?
|
682
|
+
end
|
683
|
+
|
684
|
+
def test_association_callback_ordering
|
685
|
+
Post.reset_log
|
686
|
+
log = Post.log
|
687
|
+
post = posts(:thinking)
|
688
|
+
|
689
|
+
post.people_with_callbacks << people(:michael)
|
690
|
+
assert_equal [
|
691
|
+
[:added, :before, "Michael"],
|
692
|
+
[:added, :after, "Michael"]
|
693
|
+
], log.last(2)
|
694
|
+
|
695
|
+
post.people_with_callbacks.push(people(:david), Person.create!(:first_name => "Bob"), Person.new(:first_name => "Lary"))
|
696
|
+
assert_equal [
|
697
|
+
[:added, :before, "David"],
|
698
|
+
[:added, :after, "David"],
|
699
|
+
[:added, :before, "Bob"],
|
700
|
+
[:added, :after, "Bob"],
|
701
|
+
[:added, :before, "Lary"],
|
702
|
+
[:added, :after, "Lary"]
|
703
|
+
],log.last(6)
|
704
|
+
|
705
|
+
post.people_with_callbacks.build(:first_name => "Ted")
|
706
|
+
assert_equal [
|
707
|
+
[:added, :before, "Ted"],
|
708
|
+
[:added, :after, "Ted"]
|
709
|
+
], log.last(2)
|
710
|
+
|
711
|
+
post.people_with_callbacks.create(:first_name => "Sam")
|
712
|
+
assert_equal [
|
713
|
+
[:added, :before, "Sam"],
|
714
|
+
[:added, :after, "Sam"]
|
715
|
+
], log.last(2)
|
716
|
+
|
717
|
+
post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")]
|
718
|
+
assert_equal((%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort)
|
719
|
+
assert_equal [
|
720
|
+
[:added, :before, "Julian"],
|
721
|
+
[:added, :after, "Julian"],
|
722
|
+
[:added, :before, "Roger"],
|
723
|
+
[:added, :after, "Roger"]
|
724
|
+
], log.last(4)
|
725
|
+
end
|
726
|
+
|
727
|
+
def test_dynamic_find_should_respect_association_include
|
728
|
+
# SQL error in sort clause if :include is not included
|
729
|
+
# due to Unknown column 'comments.id'
|
730
|
+
assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog')
|
731
|
+
end
|
732
|
+
|
733
|
+
def test_count_with_include_should_alias_join_table
|
734
|
+
assert_equal 2, people(:michael).posts.includes(:readers).count
|
735
|
+
end
|
736
|
+
|
737
|
+
def test_inner_join_with_quoted_table_name
|
738
|
+
assert_equal 2, people(:michael).jobs.size
|
739
|
+
end
|
740
|
+
|
741
|
+
def test_get_ids
|
742
|
+
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
|
743
|
+
end
|
744
|
+
|
745
|
+
def test_get_ids_for_has_many_through_with_conditions_should_not_preload
|
746
|
+
Tagging.create!(:taggable_type => 'Post', :taggable_id => posts(:welcome).id, :tag => tags(:misc))
|
747
|
+
ActiveRecord::Associations::Preloader.expects(:new).never
|
748
|
+
posts(:welcome).misc_tag_ids
|
749
|
+
end
|
750
|
+
|
751
|
+
def test_get_ids_for_loaded_associations
|
752
|
+
person = people(:michael)
|
753
|
+
person.posts(true)
|
754
|
+
assert_queries(0) do
|
755
|
+
person.post_ids
|
756
|
+
person.post_ids
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
def test_get_ids_for_unloaded_associations_does_not_load_them
|
761
|
+
person = people(:michael)
|
762
|
+
assert !person.posts.loaded?
|
763
|
+
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
|
764
|
+
assert !person.posts.loaded?
|
765
|
+
end
|
766
|
+
|
767
|
+
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
768
|
+
Tag.expects(:transaction)
|
769
|
+
Post.first.tags.transaction do
|
770
|
+
# nothing
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
|
775
|
+
post = Post.create!(:title => "TITLE", :body => "BODY")
|
776
|
+
assert_equal [], post.author_favorites
|
777
|
+
end
|
778
|
+
|
779
|
+
def test_has_many_association_through_a_belongs_to_association
|
780
|
+
author = authors(:mary)
|
781
|
+
post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
|
782
|
+
author.author_favorites.create(:favorite_author_id => 1)
|
783
|
+
author.author_favorites.create(:favorite_author_id => 2)
|
784
|
+
author.author_favorites.create(:favorite_author_id => 3)
|
785
|
+
assert_equal post.author.author_favorites, post.author_favorites
|
786
|
+
end
|
787
|
+
|
788
|
+
def test_merge_join_association_with_has_many_through_association_proxy
|
789
|
+
author = authors(:mary)
|
790
|
+
assert_nothing_raised { author.comments.ratings.to_sql }
|
791
|
+
end
|
792
|
+
|
793
|
+
def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
|
794
|
+
assert_equal 2, owners(:blackbeard).toys.count
|
795
|
+
end
|
796
|
+
|
797
|
+
def test_find_on_has_many_association_collection_with_include_and_conditions
|
798
|
+
post_with_no_comments = people(:michael).posts_with_no_comments.first
|
799
|
+
assert_equal post_with_no_comments, posts(:authorless)
|
800
|
+
end
|
801
|
+
|
802
|
+
def test_has_many_through_has_one_reflection
|
803
|
+
assert_equal [comments(:eager_sti_on_associations_vs_comment)], authors(:david).very_special_comments
|
804
|
+
end
|
805
|
+
|
806
|
+
def test_modifying_has_many_through_has_one_reflection_should_raise
|
807
|
+
[
|
808
|
+
lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(:body => "Gorp!", :post_id => 1011), VerySpecialComment.create!(:body => "Eep!", :post_id => 1012)] },
|
809
|
+
lambda { authors(:david).very_special_comments << VerySpecialComment.create!(:body => "Hoohah!", :post_id => 1013) },
|
810
|
+
lambda { authors(:david).very_special_comments.delete(authors(:david).very_special_comments.first) },
|
811
|
+
].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
|
812
|
+
end
|
813
|
+
|
814
|
+
def test_has_many_association_through_a_has_many_association_to_self
|
815
|
+
sarah = Person.create!(:first_name => 'Sarah', :primary_contact_id => people(:susan).id, :gender => 'F', :number1_fan_id => 1)
|
816
|
+
john = Person.create!(:first_name => 'John', :primary_contact_id => sarah.id, :gender => 'M', :number1_fan_id => 1)
|
817
|
+
assert_equal sarah.agents, [john]
|
818
|
+
assert_equal people(:susan).agents.flat_map(&:agents), people(:susan).agents_of_agents
|
819
|
+
end
|
820
|
+
|
821
|
+
def test_associate_existing_with_nonstandard_primary_key_on_belongs_to
|
822
|
+
Categorization.create(:author => authors(:mary), :named_category_name => categories(:general).name)
|
823
|
+
assert_equal categories(:general), authors(:mary).named_categories.first
|
824
|
+
end
|
825
|
+
|
826
|
+
def test_collection_build_with_nonstandard_primary_key_on_belongs_to
|
827
|
+
author = authors(:mary)
|
828
|
+
category = author.named_categories.build(:name => "Primary")
|
829
|
+
author.save
|
830
|
+
assert Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
|
831
|
+
assert author.named_categories(true).include?(category)
|
832
|
+
end
|
833
|
+
|
834
|
+
def test_collection_create_with_nonstandard_primary_key_on_belongs_to
|
835
|
+
author = authors(:mary)
|
836
|
+
category = author.named_categories.create(:name => "Primary")
|
837
|
+
assert Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
|
838
|
+
assert author.named_categories(true).include?(category)
|
839
|
+
end
|
840
|
+
|
841
|
+
def test_collection_exists
|
842
|
+
author = authors(:mary)
|
843
|
+
category = Category.create!(author_ids: [author.id], name: "Primary")
|
844
|
+
assert category.authors.exists?(id: author.id)
|
845
|
+
assert category.reload.authors.exists?(id: author.id)
|
846
|
+
end
|
847
|
+
|
848
|
+
def test_collection_delete_with_nonstandard_primary_key_on_belongs_to
|
849
|
+
author = authors(:mary)
|
850
|
+
category = author.named_categories.create(:name => "Primary")
|
851
|
+
author.named_categories.delete(category)
|
852
|
+
assert !Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
|
853
|
+
assert author.named_categories(true).empty?
|
854
|
+
end
|
855
|
+
|
856
|
+
def test_collection_singular_ids_getter_with_string_primary_keys
|
857
|
+
book = books(:awdr)
|
858
|
+
assert_equal 2, book.subscriber_ids.size
|
859
|
+
assert_equal [subscribers(:first).nick, subscribers(:second).nick].sort, book.subscriber_ids.sort
|
860
|
+
end
|
861
|
+
|
862
|
+
def test_collection_singular_ids_setter
|
863
|
+
company = companies(:rails_core)
|
864
|
+
dev = Developer.first
|
865
|
+
|
866
|
+
company.developer_ids = [dev.id]
|
867
|
+
assert_equal [dev], company.developers
|
868
|
+
end
|
869
|
+
|
870
|
+
def test_collection_singular_ids_setter_with_string_primary_keys
|
871
|
+
assert_nothing_raised do
|
872
|
+
book = books(:awdr)
|
873
|
+
book.subscriber_ids = [subscribers(:second).nick]
|
874
|
+
assert_equal [subscribers(:second)], book.subscribers(true)
|
875
|
+
|
876
|
+
book.subscriber_ids = []
|
877
|
+
assert_equal [], book.subscribers(true)
|
878
|
+
end
|
879
|
+
|
880
|
+
end
|
881
|
+
|
882
|
+
def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set
|
883
|
+
company = companies(:rails_core)
|
884
|
+
ids = [Developer.first.id, -9999]
|
885
|
+
assert_raises(ActiveRecord::RecordNotFound) {company.developer_ids= ids}
|
886
|
+
end
|
887
|
+
|
888
|
+
def test_build_a_model_from_hm_through_association_with_where_clause
|
889
|
+
assert_nothing_raised { books(:awdr).subscribers.where(:nick => "marklazz").build }
|
890
|
+
end
|
891
|
+
|
892
|
+
def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_where_clause
|
893
|
+
new_subscriber = books(:awdr).subscribers.where(:nick => "marklazz").build
|
894
|
+
assert_equal new_subscriber.nick, "marklazz"
|
895
|
+
end
|
896
|
+
|
897
|
+
def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_multiple_where_clauses
|
898
|
+
new_subscriber = books(:awdr).subscribers.where(:nick => "marklazz").where(:name => 'Marcelo Giorgi').build
|
899
|
+
assert_equal new_subscriber.nick, "marklazz"
|
900
|
+
assert_equal new_subscriber.name, "Marcelo Giorgi"
|
901
|
+
end
|
902
|
+
|
903
|
+
def test_include_method_in_association_through_should_return_true_for_instance_added_with_build
|
904
|
+
person = Person.new
|
905
|
+
reference = person.references.build
|
906
|
+
job = reference.build_job
|
907
|
+
assert person.jobs.include?(job)
|
908
|
+
end
|
909
|
+
|
910
|
+
def test_include_method_in_association_through_should_return_true_for_instance_added_with_nested_builds
|
911
|
+
author = Author.new
|
912
|
+
post = author.posts.build
|
913
|
+
comment = post.comments.build
|
914
|
+
assert author.comments.include?(comment)
|
915
|
+
end
|
916
|
+
|
917
|
+
def test_through_association_readonly_should_be_false
|
918
|
+
assert !people(:michael).posts.first.readonly?
|
919
|
+
assert !people(:michael).posts.to_a.first.readonly?
|
920
|
+
end
|
921
|
+
|
922
|
+
def test_can_update_through_association
|
923
|
+
assert_nothing_raised do
|
924
|
+
people(:michael).posts.first.update!(title: "Can write")
|
925
|
+
end
|
926
|
+
end
|
927
|
+
|
928
|
+
def test_has_many_through_polymorphic_with_primary_key_option
|
929
|
+
assert_equal [categories(:general)], authors(:david).essay_categories
|
930
|
+
|
931
|
+
authors = Author.joins(:essay_categories).where('categories.id' => categories(:general).id)
|
932
|
+
assert_equal authors(:david), authors.first
|
933
|
+
|
934
|
+
assert_equal [owners(:blackbeard)], authors(:david).essay_owners
|
935
|
+
|
936
|
+
authors = Author.joins(:essay_owners).where("owners.name = 'blackbeard'")
|
937
|
+
assert_equal authors(:david), authors.first
|
938
|
+
end
|
939
|
+
|
940
|
+
def test_has_many_through_with_primary_key_option
|
941
|
+
assert_equal [categories(:general)], authors(:david).essay_categories_2
|
942
|
+
|
943
|
+
authors = Author.joins(:essay_categories_2).where('categories.id' => categories(:general).id)
|
944
|
+
assert_equal authors(:david), authors.first
|
945
|
+
end
|
946
|
+
|
947
|
+
def test_size_of_through_association_should_increase_correctly_when_has_many_association_is_added
|
948
|
+
post = posts(:thinking)
|
949
|
+
readers = post.readers.size
|
950
|
+
post.people << people(:michael)
|
951
|
+
assert_equal readers + 1, post.readers.size
|
952
|
+
end
|
953
|
+
|
954
|
+
def test_has_many_through_with_default_scope_on_join_model
|
955
|
+
assert_equal posts(:welcome).comments.order('id').to_a, authors(:david).comments_on_first_posts
|
956
|
+
end
|
957
|
+
|
958
|
+
def test_create_has_many_through_with_default_scope_on_join_model
|
959
|
+
category = authors(:david).special_categories.create(:name => "Foo")
|
960
|
+
assert_equal 1, category.categorizations.where(:special => true).count
|
961
|
+
end
|
962
|
+
|
963
|
+
def test_joining_has_many_through_with_uniq
|
964
|
+
mary = Author.joins(:unique_categorized_posts).where(:id => authors(:mary).id).first
|
965
|
+
assert_equal 1, mary.unique_categorized_posts.length
|
966
|
+
assert_equal 1, mary.unique_categorized_post_ids.length
|
967
|
+
end
|
968
|
+
|
969
|
+
def test_joining_has_many_through_belongs_to
|
970
|
+
posts = Post.joins(:author_categorizations).order('posts.id').
|
971
|
+
where('categorizations.id' => categorizations(:mary_thinking_sti).id)
|
972
|
+
|
973
|
+
assert_equal [posts(:eager_other), posts(:misc_by_mary), posts(:other_by_mary)], posts
|
974
|
+
end
|
975
|
+
|
976
|
+
def test_select_chosen_fields_only
|
977
|
+
author = authors(:david)
|
978
|
+
assert_equal ['body', 'id'].sort, author.comments.select('comments.body').first.attributes.keys.sort
|
979
|
+
end
|
980
|
+
|
981
|
+
def test_get_has_many_through_belongs_to_ids_with_conditions
|
982
|
+
assert_equal [categories(:general).id], authors(:mary).categories_like_general_ids
|
983
|
+
end
|
984
|
+
|
985
|
+
def test_get_collection_singular_ids_on_has_many_through_with_conditions_and_include
|
986
|
+
person = Person.first
|
987
|
+
assert_equal person.posts_with_no_comment_ids, person.posts_with_no_comments.map(&:id)
|
988
|
+
end
|
989
|
+
|
990
|
+
def test_count_has_many_through_with_named_scope
|
991
|
+
assert_equal 2, authors(:mary).categories.count
|
992
|
+
assert_equal 1, authors(:mary).categories.general.count
|
993
|
+
end
|
994
|
+
|
995
|
+
def test_has_many_through_belongs_to_should_update_when_the_through_foreign_key_changes
|
996
|
+
post = posts(:eager_other)
|
997
|
+
|
998
|
+
post.author_categorizations
|
999
|
+
proxy = post.send(:association_instance_get, :author_categorizations)
|
1000
|
+
|
1001
|
+
assert !proxy.stale_target?
|
1002
|
+
assert_equal authors(:mary).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
|
1003
|
+
|
1004
|
+
post.author_id = authors(:david).id
|
1005
|
+
|
1006
|
+
assert proxy.stale_target?
|
1007
|
+
assert_equal authors(:david).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
def test_create_with_conditions_hash_on_through_association
|
1011
|
+
member = members(:groucho)
|
1012
|
+
club = member.clubs.create!
|
1013
|
+
|
1014
|
+
assert_equal true, club.reload.membership.favourite
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def test_deleting_from_has_many_through_a_belongs_to_should_not_try_to_update_counter
|
1018
|
+
post = posts(:welcome)
|
1019
|
+
address = author_addresses(:david_address)
|
1020
|
+
|
1021
|
+
assert post.author_addresses.include?(address)
|
1022
|
+
post.author_addresses.delete(address)
|
1023
|
+
assert post[:author_count].nil?
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
def test_primary_key_option_on_source
|
1027
|
+
post = posts(:welcome)
|
1028
|
+
category = categories(:general)
|
1029
|
+
Categorization.create!(:post_id => post.id, :named_category_name => category.name)
|
1030
|
+
|
1031
|
+
assert_equal [category], post.named_categories
|
1032
|
+
assert_equal [category.name], post.named_category_ids # checks when target loaded
|
1033
|
+
assert_equal [category.name], post.reload.named_category_ids # checks when target no loaded
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
def test_create_should_not_raise_exception_when_join_record_has_errors
|
1037
|
+
repair_validations(Categorization) do
|
1038
|
+
Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
|
1039
|
+
Category.create(:name => 'Fishing', :authors => [Author.first])
|
1040
|
+
end
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
def test_save_should_not_raise_exception_when_join_record_has_errors
|
1044
|
+
repair_validations(Categorization) do
|
1045
|
+
Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
|
1046
|
+
c = Category.create(:name => 'Fishing', :authors => [Author.first])
|
1047
|
+
c.save
|
1048
|
+
end
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
def test_assign_array_to_new_record_builds_join_records
|
1052
|
+
c = Category.new(:name => 'Fishing', :authors => [Author.first])
|
1053
|
+
assert_equal 1, c.categorizations.size
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
def test_create_bang_should_raise_exception_when_join_record_has_errors
|
1057
|
+
repair_validations(Categorization) do
|
1058
|
+
Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
|
1059
|
+
assert_raises(ActiveRecord::RecordInvalid) do
|
1060
|
+
Category.create!(:name => 'Fishing', :authors => [Author.first])
|
1061
|
+
end
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
def test_save_bang_should_raise_exception_when_join_record_has_errors
|
1066
|
+
repair_validations(Categorization) do
|
1067
|
+
Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
|
1068
|
+
c = Category.new(:name => 'Fishing', :authors => [Author.first])
|
1069
|
+
assert_raises(ActiveRecord::RecordInvalid) do
|
1070
|
+
c.save!
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
def test_create_bang_returns_falsy_when_join_record_has_errors
|
1076
|
+
repair_validations(Categorization) do
|
1077
|
+
Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
|
1078
|
+
c = Category.new(:name => 'Fishing', :authors => [Author.first])
|
1079
|
+
assert !c.save
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
def test_preloading_empty_through_association_via_joins
|
1084
|
+
person = Person.create!(:first_name => "Gaga")
|
1085
|
+
person = Person.where(:id => person.id).where('readers.id = 1 or 1=1').references(:readers).includes(:posts).to_a.first
|
1086
|
+
|
1087
|
+
assert person.posts.loaded?, 'person.posts should be loaded'
|
1088
|
+
assert_equal [], person.posts
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
def test_explicitly_joining_join_table
|
1092
|
+
assert_equal owners(:blackbeard).toys, owners(:blackbeard).toys.with_pet
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
def test_has_many_through_with_polymorphic_source
|
1096
|
+
post = tags(:general).tagged_posts.create! :title => "foo", :body => "bar"
|
1097
|
+
assert_equal [tags(:general)], post.reload.tags
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def test_has_many_through_obeys_order_on_through_association
|
1101
|
+
owner = owners(:blackbeard)
|
1102
|
+
assert owner.toys.to_sql.include?("pets.name desc")
|
1103
|
+
assert_equal ["parrot", "bulbul"], owner.toys.map { |r| r.pet.name }
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
def test_has_many_through_associations_on_new_records_use_null_relations
|
1107
|
+
person = Person.new
|
1108
|
+
|
1109
|
+
assert_no_queries(ignore_none: false) do
|
1110
|
+
assert_equal [], person.posts
|
1111
|
+
assert_equal [], person.posts.where(body: 'omg')
|
1112
|
+
assert_equal [], person.posts.pluck(:body)
|
1113
|
+
assert_equal 0, person.posts.sum(:tags_count)
|
1114
|
+
assert_equal 0, person.posts.count
|
1115
|
+
end
|
1116
|
+
end
|
1117
|
+
|
1118
|
+
def test_has_many_through_with_default_scope_on_the_target
|
1119
|
+
person = people(:michael)
|
1120
|
+
assert_equal [posts(:thinking)], person.first_posts
|
1121
|
+
|
1122
|
+
readers(:michael_authorless).update(first_post_id: 1)
|
1123
|
+
assert_equal [posts(:thinking)], person.reload.first_posts
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
def test_has_many_through_with_includes_in_through_association_scope
|
1127
|
+
assert_not_empty posts(:welcome).author_address_extra_with_address
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
def test_insert_records_via_has_many_through_association_with_scope
|
1131
|
+
club = Club.create!
|
1132
|
+
member = Member.create!
|
1133
|
+
Membership.create!(club: club, member: member)
|
1134
|
+
|
1135
|
+
club.favourites << member
|
1136
|
+
assert_equal [member], club.favourites
|
1137
|
+
|
1138
|
+
club.reload
|
1139
|
+
assert_equal [member], club.favourites
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
def test_has_many_through_unscope_default_scope
|
1143
|
+
post = Post.create!(:title => 'Beaches', :body => "I like beaches!")
|
1144
|
+
Reader.create! :person => people(:david), :post => post
|
1145
|
+
LazyReader.create! :person => people(:susan), :post => post
|
1146
|
+
|
1147
|
+
assert_equal 2, post.people.to_a.size
|
1148
|
+
assert_equal 1, post.lazy_people.to_a.size
|
1149
|
+
|
1150
|
+
assert_equal 2, post.lazy_readers_unscope_skimmers.to_a.size
|
1151
|
+
assert_equal 2, post.lazy_people_unscope_skimmers.to_a.size
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
def test_has_many_through_add_with_sti_middle_relation
|
1155
|
+
club = SuperClub.create!(name: 'Fight Club')
|
1156
|
+
member = Member.create!(name: 'Tyler Durden')
|
1157
|
+
|
1158
|
+
club.members << member
|
1159
|
+
assert_equal 1, SuperMembership.where(member_id: member.id, club_id: club.id).count
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
def test_build_for_has_many_through_association
|
1163
|
+
organization = organizations(:nsa)
|
1164
|
+
author = organization.author
|
1165
|
+
post_direct = author.posts.build
|
1166
|
+
post_through = organization.posts.build
|
1167
|
+
assert_equal post_direct.author_id, post_through.author_id
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
def test_has_many_through_with_scope_that_should_not_be_fully_merged
|
1171
|
+
Club.has_many :distinct_memberships, -> { distinct }, class_name: "Membership"
|
1172
|
+
Club.has_many :special_favourites, through: :distinct_memberships, source: :member
|
1173
|
+
|
1174
|
+
assert_nil Club.new.special_favourites.distinct_value
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
def test_has_many_through_do_not_cache_association_reader_if_the_though_method_has_default_scopes
|
1178
|
+
member = Member.create!
|
1179
|
+
club = Club.create!
|
1180
|
+
TenantMembership.create!(
|
1181
|
+
member: member,
|
1182
|
+
club: club
|
1183
|
+
)
|
1184
|
+
|
1185
|
+
TenantMembership.current_member = member
|
1186
|
+
|
1187
|
+
tenant_clubs = member.tenant_clubs
|
1188
|
+
assert_equal [club], tenant_clubs
|
1189
|
+
|
1190
|
+
TenantMembership.current_member = nil
|
1191
|
+
|
1192
|
+
other_member = Member.create!
|
1193
|
+
other_club = Club.create!
|
1194
|
+
TenantMembership.create!(
|
1195
|
+
member: other_member,
|
1196
|
+
club: other_club
|
1197
|
+
)
|
1198
|
+
|
1199
|
+
tenant_clubs = other_member.tenant_clubs
|
1200
|
+
assert_equal [other_club], tenant_clubs
|
1201
|
+
ensure
|
1202
|
+
TenantMembership.current_member = nil
|
1203
|
+
end
|
1204
|
+
end
|