shoulda-matchers 3.1.0 → 5.2.0
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 +5 -5
- data/{MIT-LICENSE → LICENSE} +1 -1
- data/README.md +407 -232
- data/docs/errors/NonCaseSwappableValueError.md +2 -2
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +7 -80
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +4 -3
- data/lib/shoulda/matchers/action_controller/flash_store.rb +2 -4
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +36 -30
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +8 -10
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +7 -9
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +18 -15
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +3 -2
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +3 -3
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +88 -29
- data/lib/shoulda/matchers/action_controller/route_params.rb +2 -2
- data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +4 -4
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -3
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +19 -13
- data/lib/shoulda/matchers/action_controller.rb +2 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +5 -9
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +2 -2
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +42 -39
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +52 -26
- data/lib/shoulda/matchers/active_model/helpers.rb +2 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +32 -30
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +2 -1
- data/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
- data/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb +26 -0
- data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +1 -1
- data/lib/shoulda/matchers/active_model/qualifiers.rb +2 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -6
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +8 -3
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +31 -16
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +52 -16
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +137 -84
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +159 -46
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +130 -66
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +251 -24
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +12 -9
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +38 -6
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +2 -4
- data/lib/shoulda/matchers/active_model/validator.rb +4 -9
- data/lib/shoulda/matchers/active_model.rb +3 -5
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +10 -7
- data/lib/shoulda/matchers/active_record/association_matcher.rb +386 -111
- data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +5 -2
- data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -4
- data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +11 -6
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +14 -15
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +30 -8
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +34 -11
- data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +69 -0
- data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +74 -0
- data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +3 -2
- data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +7 -5
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +458 -42
- data/lib/shoulda/matchers/active_record/have_attached_matcher.rb +185 -0
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +63 -23
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +164 -48
- data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +106 -0
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +13 -11
- data/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
- data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +132 -0
- data/lib/shoulda/matchers/active_record/serialize_matcher.rb +18 -18
- data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -3
- data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +0 -2
- data/lib/shoulda/matchers/active_record/uniqueness.rb +1 -1
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +430 -200
- data/lib/shoulda/matchers/active_record.rb +28 -20
- data/lib/shoulda/matchers/configuration.rb +12 -1
- data/lib/shoulda/matchers/doublespeak/double.rb +1 -1
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +3 -3
- data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +8 -5
- data/lib/shoulda/matchers/doublespeak/object_double.rb +6 -2
- data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +1 -5
- data/lib/shoulda/matchers/doublespeak/world.rb +2 -2
- data/lib/shoulda/matchers/doublespeak.rb +2 -1
- data/lib/shoulda/matchers/error.rb +1 -1
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +109 -29
- data/lib/shoulda/matchers/independent.rb +2 -2
- data/lib/shoulda/matchers/integrations/configuration.rb +8 -4
- data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
- data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -2
- data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
- data/lib/shoulda/matchers/rails_shim.rb +172 -51
- data/lib/shoulda/matchers/routing.rb +2 -2
- data/lib/shoulda/matchers/util/word_wrap.rb +17 -12
- data/lib/shoulda/matchers/util.rb +39 -5
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers/warn.rb +4 -3
- data/shoulda-matchers.gemspec +33 -15
- metadata +31 -338
- data/.gitignore +0 -12
- data/.hound.yml +0 -3
- data/.hound_config/ruby.yml +0 -12
- data/.travis.yml +0 -19
- data/.yardopts +0 -10
- data/Appraisals +0 -73
- data/CONTRIBUTING.md +0 -101
- data/Gemfile +0 -15
- data/Gemfile.lock +0 -70
- data/NEWS.md +0 -986
- data/Rakefile +0 -39
- data/custom_plan.rb +0 -88
- data/doc_config/gh-pages/index.html.erb +0 -9
- data/doc_config/yard/setup.rb +0 -22
- data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +0 -5967
- data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +0 -12
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +0 -62
- data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +0 -69
- data/doc_config/yard/templates/default/fulldoc/html/css/style.css +0 -312
- data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -32
- data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +0 -1
- data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +0 -8
- data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -298
- data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +0 -1
- data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +0 -289
- data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +0 -6
- data/doc_config/yard/templates/default/fulldoc/html/setup.rb +0 -8
- data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +0 -14
- data/doc_config/yard/templates/default/layout/html/fonts.erb +0 -1
- data/doc_config/yard/templates/default/layout/html/footer.erb +0 -6
- data/doc_config/yard/templates/default/layout/html/layout.erb +0 -23
- data/doc_config/yard/templates/default/layout/html/search.erb +0 -13
- data/doc_config/yard/templates/default/layout/html/setup.rb +0 -40
- data/doc_config/yard/templates/default/method_details/html/source.erb +0 -10
- data/doc_config/yard/templates/default/module/html/box_info.erb +0 -31
- data/gemfiles/4.0.0.gemfile +0 -38
- data/gemfiles/4.0.0.gemfile.lock +0 -223
- data/gemfiles/4.0.1.gemfile +0 -38
- data/gemfiles/4.0.1.gemfile.lock +0 -225
- data/gemfiles/4.1.gemfile +0 -38
- data/gemfiles/4.1.gemfile.lock +0 -220
- data/gemfiles/4.2.gemfile +0 -38
- data/gemfiles/4.2.gemfile.lock +0 -243
- data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +0 -159
- data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +0 -37
- data/script/SUPPORTED_VERSIONS +0 -1
- data/script/install_gems_in_all_appraisals +0 -14
- data/script/run_all_tests +0 -14
- data/script/update_gem_in_all_appraisals +0 -15
- data/script/update_gems_in_all_appraisals +0 -14
- data/spec/acceptance/active_model_integration_spec.rb +0 -23
- data/spec/acceptance/independent_matchers_spec.rb +0 -125
- data/spec/acceptance/multiple_libraries_integration_spec.rb +0 -55
- data/spec/acceptance/rails_integration_spec.rb +0 -156
- data/spec/acceptance_spec_helper.rb +0 -23
- data/spec/doublespeak_spec_helper.rb +0 -2
- data/spec/report_warnings.rb +0 -7
- data/spec/spec_helper.rb +0 -21
- data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +0 -133
- data/spec/support/acceptance/helpers/active_model_helpers.rb +0 -11
- data/spec/support/acceptance/helpers/array_helpers.rb +0 -13
- data/spec/support/acceptance/helpers/base_helpers.rb +0 -19
- data/spec/support/acceptance/helpers/command_helpers.rb +0 -55
- data/spec/support/acceptance/helpers/file_helpers.rb +0 -19
- data/spec/support/acceptance/helpers/gem_helpers.rb +0 -31
- data/spec/support/acceptance/helpers/minitest_helpers.rb +0 -11
- data/spec/support/acceptance/helpers/n_unit_helpers.rb +0 -25
- data/spec/support/acceptance/helpers/pluralization_helpers.rb +0 -13
- data/spec/support/acceptance/helpers/rails_version_helpers.rb +0 -11
- data/spec/support/acceptance/helpers/rspec_helpers.rb +0 -24
- data/spec/support/acceptance/helpers/ruby_version_helpers.rb +0 -9
- data/spec/support/acceptance/helpers/step_helpers.rb +0 -127
- data/spec/support/acceptance/helpers.rb +0 -31
- data/spec/support/acceptance/matchers/have_output.rb +0 -31
- data/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +0 -55
- data/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +0 -103
- data/spec/support/tests/bundle.rb +0 -94
- data/spec/support/tests/command_runner.rb +0 -230
- data/spec/support/tests/current_bundle.rb +0 -61
- data/spec/support/tests/database.rb +0 -28
- data/spec/support/tests/database_adapters/postgresql.rb +0 -25
- data/spec/support/tests/database_adapters/sqlite3.rb +0 -26
- data/spec/support/tests/database_configuration.rb +0 -33
- data/spec/support/tests/database_configuration_registry.rb +0 -28
- data/spec/support/tests/filesystem.rb +0 -100
- data/spec/support/tests/version.rb +0 -45
- data/spec/support/unit/active_record/create_table.rb +0 -54
- data/spec/support/unit/attribute.rb +0 -47
- data/spec/support/unit/capture.rb +0 -40
- data/spec/support/unit/change_value.rb +0 -111
- data/spec/support/unit/create_model_arguments/basic.rb +0 -135
- data/spec/support/unit/create_model_arguments/has_many.rb +0 -15
- data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +0 -74
- data/spec/support/unit/helpers/active_model_helpers.rb +0 -27
- data/spec/support/unit/helpers/active_model_versions.rb +0 -28
- data/spec/support/unit/helpers/active_record_versions.rb +0 -24
- data/spec/support/unit/helpers/active_resource_builder.rb +0 -27
- data/spec/support/unit/helpers/allow_value_matcher_helpers.rb +0 -15
- data/spec/support/unit/helpers/class_builder.rb +0 -90
- data/spec/support/unit/helpers/column_type_helpers.rb +0 -26
- data/spec/support/unit/helpers/confirmation_matcher_helpers.rb +0 -17
- data/spec/support/unit/helpers/controller_builder.rb +0 -63
- data/spec/support/unit/helpers/database_helpers.rb +0 -20
- data/spec/support/unit/helpers/i18n_faker.rb +0 -15
- data/spec/support/unit/helpers/mailer_builder.rb +0 -12
- data/spec/support/unit/helpers/model_builder.rb +0 -114
- data/spec/support/unit/helpers/rails_versions.rb +0 -28
- data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +0 -44
- data/spec/support/unit/i18n.rb +0 -7
- data/spec/support/unit/load_environment.rb +0 -12
- data/spec/support/unit/matchers/deprecate.rb +0 -60
- data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +0 -51
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +0 -62
- data/spec/support/unit/matchers/print_warning_including.rb +0 -59
- data/spec/support/unit/model_creation_strategies/active_model.rb +0 -111
- data/spec/support/unit/model_creation_strategies/active_record.rb +0 -77
- data/spec/support/unit/model_creators/active_model.rb +0 -39
- data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +0 -95
- data/spec/support/unit/model_creators/active_record/has_many.rb +0 -67
- data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +0 -42
- data/spec/support/unit/model_creators/active_record.rb +0 -43
- data/spec/support/unit/model_creators/basic.rb +0 -97
- data/spec/support/unit/model_creators.rb +0 -19
- data/spec/support/unit/rails_application.rb +0 -126
- data/spec/support/unit/record_builder_with_i18n_validation_message.rb +0 -69
- data/spec/support/unit/record_validating_confirmation_builder.rb +0 -51
- data/spec/support/unit/record_with_different_error_attribute_builder.rb +0 -92
- data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +0 -79
- data/spec/support/unit/shared_examples/numerical_submatcher.rb +0 -17
- data/spec/support/unit/shared_examples/set_session_or_flash.rb +0 -360
- data/spec/support/unit/validation_matcher_scenario.rb +0 -62
- data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +0 -82
- data/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +0 -28
- data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +0 -592
- data/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +0 -42
- data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +0 -76
- data/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +0 -62
- data/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +0 -90
- data/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +0 -31
- data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +0 -330
- data/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb +0 -30
- data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +0 -67
- data/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +0 -17
- data/spec/unit/shoulda/matchers/action_controller/set_session_or_flash_matcher_spec.rb +0 -562
- data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +0 -115
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +0 -823
- data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +0 -86
- data/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +0 -20
- data/spec/unit/shoulda/matchers/active_model/helpers_spec.rb +0 -162
- data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +0 -266
- data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +0 -91
- data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +0 -149
- data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +0 -207
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +0 -1015
- data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +0 -288
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +0 -1837
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +0 -380
- data/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +0 -107
- data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +0 -1242
- data/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +0 -251
- data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +0 -168
- data/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +0 -111
- data/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +0 -85
- data/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +0 -41
- data/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb +0 -86
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +0 -1418
- data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +0 -190
- data/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +0 -21
- data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +0 -271
- data/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +0 -77
- data/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +0 -72
- data/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +0 -101
- data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +0 -80
- data/spec/unit/shoulda/matchers/doublespeak_spec.rb +0 -27
- data/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb +0 -43
- data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +0 -517
- data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +0 -242
- data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +0 -252
- data/spec/unit_spec_helper.rb +0 -46
- data/spec/warnings_spy/filesystem.rb +0 -45
- data/spec/warnings_spy/partitioner.rb +0 -36
- data/spec/warnings_spy/reader.rb +0 -53
- data/spec/warnings_spy/reporter.rb +0 -88
- data/spec/warnings_spy.rb +0 -64
- data/tasks/documentation.rb +0 -199
- data/zeus.json +0 -11
@@ -1,1242 +0,0 @@
|
|
1
|
-
require 'unit_spec_helper'
|
2
|
-
|
3
|
-
describe Shoulda::Matchers::ActiveRecord::AssociationMatcher, type: :model do
|
4
|
-
context 'belong_to' do
|
5
|
-
it 'accepts a good association with the default foreign key' do
|
6
|
-
expect(belonging_to_parent).to belong_to(:parent)
|
7
|
-
end
|
8
|
-
|
9
|
-
it 'rejects a nonexistent association' do
|
10
|
-
expect(define_model(:child).new).not_to belong_to(:parent)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'rejects an association of the wrong type' do
|
14
|
-
define_model :parent, child_id: :integer
|
15
|
-
expect(define_model(:child) { has_one :parent }.new).not_to belong_to(:parent)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'rejects an association that has a nonexistent foreign key' do
|
19
|
-
define_model :parent
|
20
|
-
expect(define_model(:child) { belongs_to :parent }.new).not_to belong_to(:parent)
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'accepts an association with an existing custom foreign key' do
|
24
|
-
define_model :parent
|
25
|
-
define_model :child, guardian_id: :integer do
|
26
|
-
belongs_to :parent, foreign_key: 'guardian_id'
|
27
|
-
end
|
28
|
-
|
29
|
-
expect(Child.new).to belong_to(:parent)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'accepts an association using an existing custom primary key' do
|
33
|
-
define_model :parent
|
34
|
-
define_model :child, parent_id: :integer, custom_primary_key: :integer do
|
35
|
-
belongs_to :parent, primary_key: :custom_primary_key
|
36
|
-
end
|
37
|
-
expect(Child.new).to belong_to(:parent).with_primary_key(:custom_primary_key)
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'rejects an association with a bad :primary_key option' do
|
41
|
-
matcher = belong_to(:parent).with_primary_key(:custom_primary_key)
|
42
|
-
|
43
|
-
expect(belonging_to_parent).not_to matcher
|
44
|
-
|
45
|
-
expect(matcher.failure_message).to match(/Child does not have a custom_primary_key primary key/)
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'accepts a polymorphic association' do
|
49
|
-
define_model :child, parent_type: :string, parent_id: :integer do
|
50
|
-
belongs_to :parent, polymorphic: true
|
51
|
-
end
|
52
|
-
|
53
|
-
expect(Child.new).to belong_to(:parent)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'accepts an association with a valid :dependent option' do
|
57
|
-
expect(belonging_to_parent(dependent: :destroy)).
|
58
|
-
to belong_to(:parent).dependent(:destroy)
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'rejects an association with a bad :dependent option' do
|
62
|
-
expect(belonging_to_parent).not_to belong_to(:parent).dependent(:destroy)
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'accepts an association with a valid :counter_cache option' do
|
66
|
-
expect(belonging_to_parent(counter_cache: :attribute_count)).
|
67
|
-
to belong_to(:parent).counter_cache(:attribute_count)
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'defaults :counter_cache to true' do
|
71
|
-
expect(belonging_to_parent(counter_cache: true)).
|
72
|
-
to belong_to(:parent).counter_cache
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'rejects an association with a bad :counter_cache option' do
|
76
|
-
expect(belonging_to_parent(counter_cache: :attribute_count)).
|
77
|
-
not_to belong_to(:parent).counter_cache(true)
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'rejects an association that has no :counter_cache option' do
|
81
|
-
expect(belonging_to_parent).not_to belong_to(:parent).counter_cache
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'accepts an association with a valid :inverse_of option' do
|
85
|
-
expect(belonging_to_parent(inverse_of: :children))
|
86
|
-
.to belong_to(:parent).inverse_of(:children)
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'rejects an association with a bad :inverse_of option' do
|
90
|
-
expect(belonging_to_parent(inverse_of: :other_children))
|
91
|
-
.not_to belong_to(:parent).inverse_of(:children)
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'rejects an association that has no :inverse_of option' do
|
95
|
-
expect(belonging_to_parent)
|
96
|
-
.not_to belong_to(:parent).inverse_of(:children)
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'accepts an association with a valid :conditions option' do
|
100
|
-
define_model :parent, adopter: :boolean
|
101
|
-
define_model(:child, parent_id: :integer).tap do |model|
|
102
|
-
define_association_with_conditions(model, :belongs_to, :parent, adopter: true)
|
103
|
-
end
|
104
|
-
|
105
|
-
expect(Child.new).to belong_to(:parent).conditions(adopter: true)
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'rejects an association with a bad :conditions option' do
|
109
|
-
define_model :parent, adopter: :boolean
|
110
|
-
define_model :child, parent_id: :integer do
|
111
|
-
belongs_to :parent
|
112
|
-
end
|
113
|
-
|
114
|
-
expect(Child.new).not_to belong_to(:parent).conditions(adopter: true)
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'accepts an association without a :class_name option' do
|
118
|
-
expect(belonging_to_parent).to belong_to(:parent).class_name('Parent')
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'accepts an association with a valid :class_name option' do
|
122
|
-
define_model :tree_parent
|
123
|
-
define_model :child, parent_id: :integer do
|
124
|
-
belongs_to :parent, class_name: 'TreeParent'
|
125
|
-
end
|
126
|
-
|
127
|
-
expect(Child.new).to belong_to(:parent).class_name('TreeParent')
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'rejects an association with a bad :class_name option' do
|
131
|
-
expect(belonging_to_parent).not_to belong_to(:parent).class_name('TreeChild')
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'rejects an association with non-existent implicit class name' do
|
135
|
-
expect(belonging_to_non_existent_class(:child, :parent)).not_to belong_to(:parent)
|
136
|
-
end
|
137
|
-
|
138
|
-
it 'rejects an association with non-existent explicit class name' do
|
139
|
-
expect(belonging_to_non_existent_class(:child, :parent, class_name: 'Parent')).not_to belong_to(:parent)
|
140
|
-
end
|
141
|
-
|
142
|
-
it 'adds error message when rejecting an association with non-existent class' do
|
143
|
-
message = 'Expected Child to have a belongs_to association called parent (Parent2 does not exist)'
|
144
|
-
expect {
|
145
|
-
expect(belonging_to_non_existent_class(:child, :parent, class_name: 'Parent2')).to belong_to(:parent)
|
146
|
-
}.to fail_with_message(message)
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'accepts an association with a namespaced class name' do
|
150
|
-
define_module 'Models'
|
151
|
-
define_model 'Models::Organization'
|
152
|
-
user_model = define_model 'Models::User', organization_id: :integer do
|
153
|
-
belongs_to :organization, class_name: 'Organization'
|
154
|
-
end
|
155
|
-
|
156
|
-
expect(user_model.new).
|
157
|
-
to belong_to(:organization).
|
158
|
-
class_name('Organization')
|
159
|
-
end
|
160
|
-
|
161
|
-
it 'resolves class_name within the context of the namespace before the global namespace' do
|
162
|
-
define_module 'Models'
|
163
|
-
define_model 'Organization'
|
164
|
-
define_model 'Models::Organization'
|
165
|
-
user_model = define_model 'Models::User', organization_id: :integer do
|
166
|
-
belongs_to :organization, class_name: 'Organization'
|
167
|
-
end
|
168
|
-
|
169
|
-
expect(user_model.new).
|
170
|
-
to belong_to(:organization).
|
171
|
-
class_name('Organization')
|
172
|
-
end
|
173
|
-
|
174
|
-
it 'accepts an association with a matching :autosave option' do
|
175
|
-
define_model :parent, adopter: :boolean
|
176
|
-
define_model :child, parent_id: :integer do
|
177
|
-
belongs_to :parent, autosave: true
|
178
|
-
end
|
179
|
-
expect(Child.new).to belong_to(:parent).autosave(true)
|
180
|
-
end
|
181
|
-
|
182
|
-
it 'rejects an association with a non-matching :autosave option with the correct message' do
|
183
|
-
define_model :parent, adopter: :boolean
|
184
|
-
define_model :child, parent_id: :integer do
|
185
|
-
belongs_to :parent, autosave: false
|
186
|
-
end
|
187
|
-
|
188
|
-
message = 'Expected Child to have a belongs_to association called parent (parent should have autosave set to true)'
|
189
|
-
expect {
|
190
|
-
expect(Child.new).to belong_to(:parent).autosave(true)
|
191
|
-
}.to fail_with_message(message)
|
192
|
-
end
|
193
|
-
|
194
|
-
context 'an association with a :validate option' do
|
195
|
-
[false, true].each do |validate_value|
|
196
|
-
context "when the model has validate: #{validate_value}" do
|
197
|
-
it 'accepts a matching validate option' do
|
198
|
-
expect(belonging_to_parent(validate: validate_value)).
|
199
|
-
to belong_to(:parent).validate(validate_value)
|
200
|
-
end
|
201
|
-
|
202
|
-
it 'rejects a non-matching validate option' do
|
203
|
-
expect(belonging_to_parent(validate: validate_value)).
|
204
|
-
not_to belong_to(:parent).validate(!validate_value)
|
205
|
-
end
|
206
|
-
|
207
|
-
it 'defaults to validate(true)' do
|
208
|
-
if validate_value
|
209
|
-
expect(belonging_to_parent(validate: validate_value)).
|
210
|
-
to belong_to(:parent).validate
|
211
|
-
else
|
212
|
-
expect(belonging_to_parent(validate: validate_value)).
|
213
|
-
not_to belong_to(:parent).validate
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
it 'will not break matcher when validate option is unspecified' do
|
218
|
-
expect(belonging_to_parent(validate: validate_value)).to belong_to(:parent)
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
context 'an association without a :validate option' do
|
225
|
-
it 'accepts validate(false)' do
|
226
|
-
expect(belonging_to_parent).to belong_to(:parent).validate(false)
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'rejects validate(true)' do
|
230
|
-
expect(belonging_to_parent).not_to belong_to(:parent).validate(true)
|
231
|
-
end
|
232
|
-
|
233
|
-
it 'rejects validate()' do
|
234
|
-
expect(belonging_to_parent).not_to belong_to(:parent).validate
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
context 'an association with a :touch option' do
|
239
|
-
[false, true].each do |touch_value|
|
240
|
-
context "when the model has touch: #{touch_value}" do
|
241
|
-
it 'accepts a matching touch option' do
|
242
|
-
expect(belonging_to_parent(touch: touch_value)).
|
243
|
-
to belong_to(:parent).touch(touch_value)
|
244
|
-
end
|
245
|
-
|
246
|
-
it 'rejects a non-matching touch option' do
|
247
|
-
expect(belonging_to_parent(touch: touch_value)).
|
248
|
-
not_to belong_to(:parent).touch(!touch_value)
|
249
|
-
end
|
250
|
-
|
251
|
-
it 'defaults to touch(true)' do
|
252
|
-
if touch_value
|
253
|
-
expect(belonging_to_parent(touch: touch_value)).
|
254
|
-
to belong_to(:parent).touch
|
255
|
-
else
|
256
|
-
expect(belonging_to_parent(touch: touch_value)).
|
257
|
-
not_to belong_to(:parent).touch
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
it 'will not break matcher when touch option is unspecified' do
|
262
|
-
expect(belonging_to_parent(touch: touch_value)).to belong_to(:parent)
|
263
|
-
end
|
264
|
-
end
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
context 'an association without a :touch option' do
|
269
|
-
it 'accepts touch(false)' do
|
270
|
-
expect(belonging_to_parent).to belong_to(:parent).touch(false)
|
271
|
-
end
|
272
|
-
|
273
|
-
it 'rejects touch(true)' do
|
274
|
-
expect(belonging_to_parent).not_to belong_to(:parent).touch(true)
|
275
|
-
end
|
276
|
-
|
277
|
-
it 'rejects touch()' do
|
278
|
-
expect(belonging_to_parent).not_to belong_to(:parent).touch
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
def belonging_to_parent(options = {})
|
283
|
-
define_model :parent
|
284
|
-
define_model :child, parent_id: :integer do
|
285
|
-
belongs_to :parent, options
|
286
|
-
end.new
|
287
|
-
end
|
288
|
-
|
289
|
-
def belonging_to_non_existent_class(model_name, assoc_name, options = {})
|
290
|
-
define_model model_name, "#{assoc_name}_id" => :integer do
|
291
|
-
belongs_to assoc_name, options
|
292
|
-
end.new
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
context 'have_many' do
|
297
|
-
it 'accepts a valid association without any options' do
|
298
|
-
expect(having_many_children).to have_many(:children)
|
299
|
-
end
|
300
|
-
|
301
|
-
it 'accepts a valid association with a :through option' do
|
302
|
-
define_model :child
|
303
|
-
define_model :conception, child_id: :integer,
|
304
|
-
parent_id: :integer do
|
305
|
-
belongs_to :child
|
306
|
-
end
|
307
|
-
define_model :parent do
|
308
|
-
has_many :conceptions
|
309
|
-
has_many :children, through: :conceptions
|
310
|
-
end
|
311
|
-
expect(Parent.new).to have_many(:children)
|
312
|
-
end
|
313
|
-
|
314
|
-
it 'accepts a valid association with an :as option' do
|
315
|
-
define_model :child, guardian_type: :string, guardian_id: :integer
|
316
|
-
define_model :parent do
|
317
|
-
has_many :children, as: :guardian
|
318
|
-
end
|
319
|
-
|
320
|
-
expect(Parent.new).to have_many(:children)
|
321
|
-
end
|
322
|
-
|
323
|
-
it 'rejects an association that has a nonexistent foreign key' do
|
324
|
-
define_model :child
|
325
|
-
define_model :parent do
|
326
|
-
has_many :children
|
327
|
-
end
|
328
|
-
|
329
|
-
expect(Parent.new).not_to have_many(:children)
|
330
|
-
end
|
331
|
-
|
332
|
-
it 'accepts an association using an existing custom primary key' do
|
333
|
-
define_model :child, parent_id: :integer
|
334
|
-
define_model :parent, custom_primary_key: :integer do
|
335
|
-
has_many :children, primary_key: :custom_primary_key
|
336
|
-
end
|
337
|
-
expect(Parent.new).to have_many(:children).with_primary_key(:custom_primary_key)
|
338
|
-
end
|
339
|
-
|
340
|
-
it 'rejects an association with a bad :primary_key option' do
|
341
|
-
matcher = have_many(:children).with_primary_key(:custom_primary_key)
|
342
|
-
|
343
|
-
expect(having_many_children).not_to matcher
|
344
|
-
|
345
|
-
expect(matcher.failure_message).to match(/Parent does not have a custom_primary_key primary key/)
|
346
|
-
end
|
347
|
-
|
348
|
-
it 'rejects an association with a bad :as option' do
|
349
|
-
define_model :child, caretaker_type: :string,
|
350
|
-
caretaker_id: :integer
|
351
|
-
define_model :parent do
|
352
|
-
has_many :children, as: :guardian
|
353
|
-
end
|
354
|
-
|
355
|
-
expect(Parent.new).not_to have_many(:children)
|
356
|
-
end
|
357
|
-
|
358
|
-
it 'rejects an association that has a bad :through option' do
|
359
|
-
matcher = have_many(:children).through(:conceptions)
|
360
|
-
|
361
|
-
expect(matcher.matches?(having_many_children)).to eq false
|
362
|
-
|
363
|
-
expect(matcher.failure_message).to match(/does not have any relationship to conceptions/)
|
364
|
-
end
|
365
|
-
|
366
|
-
it 'rejects an association that has the wrong :through option' do
|
367
|
-
define_model :child
|
368
|
-
|
369
|
-
define_model :conception, child_id: :integer,
|
370
|
-
parent_id: :integer do
|
371
|
-
belongs_to :child
|
372
|
-
end
|
373
|
-
|
374
|
-
define_model :parent do
|
375
|
-
has_many :conceptions
|
376
|
-
has_many :relationships
|
377
|
-
has_many :children, through: :conceptions
|
378
|
-
end
|
379
|
-
|
380
|
-
matcher = have_many(:children).through(:relationships)
|
381
|
-
expect(matcher.matches?(Parent.new)).to eq false
|
382
|
-
expect(matcher.failure_message).to match(/through relationships, but got it through conceptions/)
|
383
|
-
end
|
384
|
-
|
385
|
-
it 'produces a failure message without exception when association is missing :through option' do
|
386
|
-
define_model :child
|
387
|
-
define_model :parent
|
388
|
-
matcher = have_many(:children).through(:relationships).source(:child)
|
389
|
-
failure_message = 'Expected Parent to have a has_many association called children (no association called children)'
|
390
|
-
|
391
|
-
matcher.matches?(Parent.new)
|
392
|
-
expect(matcher.failure_message).to eq failure_message
|
393
|
-
end
|
394
|
-
|
395
|
-
it 'accepts an association with a valid :dependent option' do
|
396
|
-
expect(having_many_children(dependent: :destroy)).
|
397
|
-
to have_many(:children).dependent(:destroy)
|
398
|
-
end
|
399
|
-
|
400
|
-
it 'rejects an association with a bad :dependent option' do
|
401
|
-
matcher = have_many(:children).dependent(:destroy)
|
402
|
-
|
403
|
-
expect(having_many_children).not_to matcher
|
404
|
-
|
405
|
-
expect(matcher.failure_message).to match(/children should have destroy dependency/)
|
406
|
-
end
|
407
|
-
|
408
|
-
it 'accepts an association with a valid :source option' do
|
409
|
-
expect(having_many_children(source: :user)).
|
410
|
-
to have_many(:children).source(:user)
|
411
|
-
end
|
412
|
-
|
413
|
-
it 'rejects an association with a bad :source option' do
|
414
|
-
matcher = have_many(:children).source(:user)
|
415
|
-
|
416
|
-
expect(having_many_children).not_to matcher
|
417
|
-
|
418
|
-
expect(matcher.failure_message).to match(/children should have user as source option/)
|
419
|
-
end
|
420
|
-
|
421
|
-
it 'accepts an association with a valid :order option' do
|
422
|
-
expect(having_many_children(order: :id)).
|
423
|
-
to have_many(:children).order(:id)
|
424
|
-
end
|
425
|
-
|
426
|
-
it 'rejects an association with a bad :order option' do
|
427
|
-
matcher = have_many(:children).order(:id)
|
428
|
-
|
429
|
-
expect(having_many_children).not_to matcher
|
430
|
-
|
431
|
-
expect(matcher.failure_message).to match(/children should be ordered by id/)
|
432
|
-
end
|
433
|
-
|
434
|
-
it 'accepts an association with a valid :conditions option' do
|
435
|
-
define_model :child, parent_id: :integer, adopted: :boolean
|
436
|
-
define_model(:parent).tap do |model|
|
437
|
-
define_association_with_conditions(model, :has_many, :children, adopted: true)
|
438
|
-
end
|
439
|
-
|
440
|
-
expect(Parent.new).to have_many(:children).conditions(adopted: true)
|
441
|
-
end
|
442
|
-
|
443
|
-
it 'rejects an association with a bad :conditions option' do
|
444
|
-
define_model :child, parent_id: :integer, adopted: :boolean
|
445
|
-
define_model :parent do
|
446
|
-
has_many :children
|
447
|
-
end
|
448
|
-
|
449
|
-
expect(Parent.new).not_to have_many(:children).conditions(adopted: true)
|
450
|
-
end
|
451
|
-
|
452
|
-
it 'accepts an association without a :class_name option' do
|
453
|
-
expect(having_many_children).to have_many(:children).class_name('Child')
|
454
|
-
end
|
455
|
-
|
456
|
-
it 'accepts an association with a valid :class_name option' do
|
457
|
-
define_model :node, parent_id: :integer
|
458
|
-
define_model :parent do
|
459
|
-
has_many :children, class_name: 'Node'
|
460
|
-
end
|
461
|
-
|
462
|
-
expect(Parent.new).to have_many(:children).class_name('Node')
|
463
|
-
end
|
464
|
-
|
465
|
-
it 'rejects an association with a bad :class_name option' do
|
466
|
-
expect(having_many_children).not_to have_many(:children).class_name('Node')
|
467
|
-
end
|
468
|
-
|
469
|
-
it 'rejects an association with non-existent implicit class name' do
|
470
|
-
expect(having_many_non_existent_class(:parent, :children)).not_to have_many(:children)
|
471
|
-
end
|
472
|
-
|
473
|
-
it 'rejects an association with non-existent explicit class name' do
|
474
|
-
expect(having_many_non_existent_class(:parent, :children, class_name: 'Child')).not_to have_many(:children)
|
475
|
-
end
|
476
|
-
|
477
|
-
it 'adds error message when rejecting an association with non-existent class' do
|
478
|
-
message = 'Expected Parent to have a has_many association called children (Child2 does not exist)'
|
479
|
-
expect {
|
480
|
-
expect(having_many_non_existent_class(:parent, :children, class_name: 'Child2')).to have_many(:children)
|
481
|
-
}.to fail_with_message(message)
|
482
|
-
end
|
483
|
-
|
484
|
-
it 'accepts an association with a namespaced class name' do
|
485
|
-
define_module 'Models'
|
486
|
-
define_model 'Models::Friend', user_id: :integer
|
487
|
-
friend_model = define_model 'Models::User' do
|
488
|
-
has_many :friends, class_name: 'Friend'
|
489
|
-
end
|
490
|
-
|
491
|
-
expect(friend_model.new).
|
492
|
-
to have_many(:friends).
|
493
|
-
class_name('Friend')
|
494
|
-
end
|
495
|
-
|
496
|
-
it 'resolves class_name within the context of the namespace before the global namespace' do
|
497
|
-
define_module 'Models'
|
498
|
-
define_model 'Friend'
|
499
|
-
define_model 'Models::Friend', user_id: :integer
|
500
|
-
friend_model = define_model 'Models::User' do
|
501
|
-
has_many :friends, class_name: 'Friend'
|
502
|
-
end
|
503
|
-
|
504
|
-
expect(friend_model.new).
|
505
|
-
to have_many(:friends).
|
506
|
-
class_name('Friend')
|
507
|
-
end
|
508
|
-
|
509
|
-
it 'accepts an association with a matching :autosave option' do
|
510
|
-
define_model :child, parent_id: :integer
|
511
|
-
define_model :parent do
|
512
|
-
has_many :children, autosave: true
|
513
|
-
end
|
514
|
-
expect(Parent.new).to have_many(:children).autosave(true)
|
515
|
-
end
|
516
|
-
|
517
|
-
it 'rejects an association with a non-matching :autosave option with the correct message' do
|
518
|
-
define_model :child, parent_id: :integer
|
519
|
-
define_model :parent do
|
520
|
-
has_many :children, autosave: false
|
521
|
-
end
|
522
|
-
|
523
|
-
message = 'Expected Parent to have a has_many association called children (children should have autosave set to true)'
|
524
|
-
expect {
|
525
|
-
expect(Parent.new).to have_many(:children).autosave(true)
|
526
|
-
}.to fail_with_message(message)
|
527
|
-
end
|
528
|
-
|
529
|
-
context 'validate' do
|
530
|
-
it 'accepts when the :validate option matches' do
|
531
|
-
expect(having_many_children(validate: false)).to have_many(:children).validate(false)
|
532
|
-
end
|
533
|
-
|
534
|
-
it 'rejects when the :validate option does not match' do
|
535
|
-
expect(having_many_children(validate: true)).not_to have_many(:children).validate(false)
|
536
|
-
end
|
537
|
-
|
538
|
-
it 'assumes validate() means validate(true)' do
|
539
|
-
expect(having_many_children(validate: false)).not_to have_many(:children).validate
|
540
|
-
end
|
541
|
-
|
542
|
-
it 'matches validate(false) to having no validate option specified' do
|
543
|
-
expect(having_many_children).to have_many(:children).validate(false)
|
544
|
-
end
|
545
|
-
end
|
546
|
-
|
547
|
-
it 'accepts an association with a nonstandard reverse foreign key, using :inverse_of' do
|
548
|
-
define_model :child, ancestor_id: :integer do
|
549
|
-
belongs_to :ancestor, inverse_of: :children, class_name: :Parent
|
550
|
-
end
|
551
|
-
|
552
|
-
define_model :parent do
|
553
|
-
has_many :children, inverse_of: :ancestor
|
554
|
-
end
|
555
|
-
|
556
|
-
expect(Parent.new).to have_many(:children)
|
557
|
-
end
|
558
|
-
|
559
|
-
it 'rejects an association with a nonstandard reverse foreign key, if :inverse_of is not correct' do
|
560
|
-
define_model :child, mother_id: :integer do
|
561
|
-
belongs_to :mother, inverse_of: :children, class_name: :Parent
|
562
|
-
end
|
563
|
-
|
564
|
-
define_model :parent do
|
565
|
-
has_many :children, inverse_of: :ancestor
|
566
|
-
end
|
567
|
-
|
568
|
-
expect(Parent.new).not_to have_many(:children)
|
569
|
-
end
|
570
|
-
|
571
|
-
def having_many_children(options = {})
|
572
|
-
define_model :child, parent_id: :integer
|
573
|
-
define_model(:parent).tap do |model|
|
574
|
-
if options.key?(:order)
|
575
|
-
order = options.delete(:order)
|
576
|
-
define_association_with_order(model, :has_many, :children, order, options)
|
577
|
-
else
|
578
|
-
model.has_many :children, options
|
579
|
-
end
|
580
|
-
end.new
|
581
|
-
end
|
582
|
-
|
583
|
-
def having_many_non_existent_class(model_name, assoc_name, options = {})
|
584
|
-
define_model model_name do
|
585
|
-
has_many assoc_name, options
|
586
|
-
end.new
|
587
|
-
end
|
588
|
-
end
|
589
|
-
|
590
|
-
context 'have_one' do
|
591
|
-
it 'accepts a valid association without any options' do
|
592
|
-
expect(having_one_detail).to have_one(:detail)
|
593
|
-
end
|
594
|
-
|
595
|
-
it 'accepts a valid association with an :as option' do
|
596
|
-
define_model :detail, detailable_id: :integer,
|
597
|
-
detailable_type: :string
|
598
|
-
define_model :person do
|
599
|
-
has_one :detail, as: :detailable
|
600
|
-
end
|
601
|
-
|
602
|
-
expect(Person.new).to have_one(:detail)
|
603
|
-
end
|
604
|
-
|
605
|
-
it 'rejects an association that has a nonexistent foreign key' do
|
606
|
-
define_model :detail
|
607
|
-
define_model :person do
|
608
|
-
has_one :detail
|
609
|
-
end
|
610
|
-
|
611
|
-
expect(Person.new).not_to have_one(:detail)
|
612
|
-
end
|
613
|
-
|
614
|
-
it 'accepts an association with an existing custom foreign key' do
|
615
|
-
define_model :detail, detailed_person_id: :integer
|
616
|
-
define_model :person do
|
617
|
-
has_one :detail, foreign_key: :detailed_person_id
|
618
|
-
end
|
619
|
-
expect(Person.new).to have_one(:detail).with_foreign_key(:detailed_person_id)
|
620
|
-
end
|
621
|
-
|
622
|
-
it 'accepts an association using an existing custom primary key' do
|
623
|
-
define_model :detail, person_id: :integer
|
624
|
-
define_model :person, custom_primary_key: :integer do
|
625
|
-
has_one :detail, primary_key: :custom_primary_key
|
626
|
-
end
|
627
|
-
expect(Person.new).to have_one(:detail).with_primary_key(:custom_primary_key)
|
628
|
-
end
|
629
|
-
|
630
|
-
it 'rejects an association with a bad :primary_key option' do
|
631
|
-
matcher = have_one(:detail).with_primary_key(:custom_primary_key)
|
632
|
-
|
633
|
-
expect(having_one_detail).not_to matcher
|
634
|
-
|
635
|
-
expect(matcher.failure_message).to match(/Person does not have a custom_primary_key primary key/)
|
636
|
-
end
|
637
|
-
|
638
|
-
it 'rejects an association with a bad :as option' do
|
639
|
-
define_model :detail, detailable_id: :integer,
|
640
|
-
detailable_type: :string
|
641
|
-
define_model :person do
|
642
|
-
has_one :detail, as: :describable
|
643
|
-
end
|
644
|
-
|
645
|
-
expect(Person.new).not_to have_one(:detail)
|
646
|
-
end
|
647
|
-
|
648
|
-
it 'accepts an association with a valid :dependent option' do
|
649
|
-
dependent_options.each do |option|
|
650
|
-
expect(having_one_detail(dependent: option)).
|
651
|
-
to have_one(:detail).dependent(option)
|
652
|
-
end
|
653
|
-
end
|
654
|
-
|
655
|
-
it 'accepts any dependent option if true' do
|
656
|
-
dependent_options.each do |option|
|
657
|
-
expect(having_one_detail(dependent: option)).
|
658
|
-
to have_one(:detail).dependent(true)
|
659
|
-
end
|
660
|
-
end
|
661
|
-
|
662
|
-
it 'rejects any dependent options if false' do
|
663
|
-
dependent_options.each do |option|
|
664
|
-
expect(having_one_detail(dependent: option)).
|
665
|
-
to_not have_one(:detail).dependent(false)
|
666
|
-
end
|
667
|
-
end
|
668
|
-
|
669
|
-
it 'accepts a nil dependent option if false' do
|
670
|
-
expect(having_one_detail).to have_one(:detail).dependent(false)
|
671
|
-
end
|
672
|
-
|
673
|
-
it 'rejects an association with a bad :dependent option' do
|
674
|
-
matcher = have_one(:detail).dependent(:destroy)
|
675
|
-
|
676
|
-
expect(having_one_detail).not_to matcher
|
677
|
-
|
678
|
-
expect(matcher.failure_message).to match(/detail should have destroy dependency/)
|
679
|
-
end
|
680
|
-
|
681
|
-
it 'accepts an association with a valid :order option' do
|
682
|
-
expect(having_one_detail(order: :id)).to have_one(:detail).order(:id)
|
683
|
-
end
|
684
|
-
|
685
|
-
it 'rejects an association with a bad :order option' do
|
686
|
-
matcher = have_one(:detail).order(:id)
|
687
|
-
|
688
|
-
expect(having_one_detail).not_to matcher
|
689
|
-
|
690
|
-
expect(matcher.failure_message).to match(/detail should be ordered by id/)
|
691
|
-
end
|
692
|
-
|
693
|
-
it 'accepts an association with a valid :conditions option' do
|
694
|
-
define_model :detail, person_id: :integer, disabled: :boolean
|
695
|
-
define_model(:person).tap do |model|
|
696
|
-
define_association_with_conditions(model, :has_one, :detail, disabled: true)
|
697
|
-
end
|
698
|
-
|
699
|
-
expect(Person.new).to have_one(:detail).conditions(disabled: true)
|
700
|
-
end
|
701
|
-
|
702
|
-
it 'rejects an association with a bad :conditions option' do
|
703
|
-
define_model :detail, person_id: :integer, disabled: :boolean
|
704
|
-
define_model :person do
|
705
|
-
has_one :detail
|
706
|
-
end
|
707
|
-
|
708
|
-
expect(Person.new).not_to have_one(:detail).conditions(disabled: true)
|
709
|
-
end
|
710
|
-
|
711
|
-
it 'accepts an association without a :class_name option' do
|
712
|
-
expect(having_one_detail).to have_one(:detail).class_name('Detail')
|
713
|
-
end
|
714
|
-
|
715
|
-
it 'accepts an association with a valid :class_name option' do
|
716
|
-
define_model :person_detail, person_id: :integer
|
717
|
-
define_model :person do
|
718
|
-
has_one :detail, class_name: 'PersonDetail'
|
719
|
-
end
|
720
|
-
|
721
|
-
expect(Person.new).to have_one(:detail).class_name('PersonDetail')
|
722
|
-
end
|
723
|
-
|
724
|
-
it 'rejects an association with a bad :class_name option' do
|
725
|
-
expect(having_one_detail).not_to have_one(:detail).class_name('NotSet')
|
726
|
-
end
|
727
|
-
|
728
|
-
it 'rejects an association with non-existent implicit class name' do
|
729
|
-
expect(having_one_non_existent(:pserson, :detail)).not_to have_one(:detail)
|
730
|
-
end
|
731
|
-
|
732
|
-
it 'rejects an association with non-existent explicit class name' do
|
733
|
-
expect(having_one_non_existent(:person, :detail, class_name: 'Detail')).not_to have_one(:detail)
|
734
|
-
end
|
735
|
-
|
736
|
-
it 'adds error message when rejecting an association with non-existent class' do
|
737
|
-
message = 'Expected Person to have a has_one association called detail (Detail2 does not exist)'
|
738
|
-
expect {
|
739
|
-
expect(having_one_non_existent(:person, :detail, class_name: 'Detail2')).to have_one(:detail)
|
740
|
-
}.to fail_with_message(message)
|
741
|
-
end
|
742
|
-
|
743
|
-
it 'accepts an association with a namespaced class name' do
|
744
|
-
define_module 'Models'
|
745
|
-
define_model 'Models::Account', user_id: :integer
|
746
|
-
user_model = define_model 'Models::User' do
|
747
|
-
has_one :account, class_name: 'Account'
|
748
|
-
end
|
749
|
-
|
750
|
-
expect(user_model.new).
|
751
|
-
to have_one(:account).
|
752
|
-
class_name('Account')
|
753
|
-
end
|
754
|
-
|
755
|
-
it 'resolves class_name within the context of the namespace before the global namespace' do
|
756
|
-
define_module 'Models'
|
757
|
-
define_model 'Account'
|
758
|
-
define_model 'Models::Account', user_id: :integer
|
759
|
-
user_model = define_model 'Models::User' do
|
760
|
-
has_one :account, class_name: 'Account'
|
761
|
-
end
|
762
|
-
|
763
|
-
expect(user_model.new).
|
764
|
-
to have_one(:account).
|
765
|
-
class_name('Account')
|
766
|
-
end
|
767
|
-
|
768
|
-
it 'accepts an association with a matching :autosave option' do
|
769
|
-
define_model :detail, person_id: :integer, disabled: :boolean
|
770
|
-
define_model :person do
|
771
|
-
has_one :detail, autosave: true
|
772
|
-
end
|
773
|
-
expect(Person.new).to have_one(:detail).autosave(true)
|
774
|
-
end
|
775
|
-
|
776
|
-
it 'rejects an association with a non-matching :autosave option with the correct message' do
|
777
|
-
define_model :detail, person_id: :integer, disabled: :boolean
|
778
|
-
define_model :person do
|
779
|
-
has_one :detail, autosave: false
|
780
|
-
end
|
781
|
-
|
782
|
-
message = 'Expected Person to have a has_one association called detail (detail should have autosave set to true)'
|
783
|
-
expect {
|
784
|
-
expect(Person.new).to have_one(:detail).autosave(true)
|
785
|
-
}.to fail_with_message(message)
|
786
|
-
end
|
787
|
-
|
788
|
-
|
789
|
-
it 'accepts an association with a through' do
|
790
|
-
define_model :detail
|
791
|
-
|
792
|
-
define_model :account do
|
793
|
-
has_one :detail
|
794
|
-
end
|
795
|
-
|
796
|
-
define_model :person do
|
797
|
-
has_one :account
|
798
|
-
has_one :detail, through: :account
|
799
|
-
end
|
800
|
-
|
801
|
-
expect(Person.new).to have_one(:detail).through(:account)
|
802
|
-
end
|
803
|
-
|
804
|
-
it 'rejects an association with a bad through' do
|
805
|
-
expect(having_one_detail).not_to have_one(:detail).through(:account)
|
806
|
-
end
|
807
|
-
|
808
|
-
context 'validate' do
|
809
|
-
it 'accepts when the :validate option matches' do
|
810
|
-
expect(having_one_detail(validate: false)).
|
811
|
-
to have_one(:detail).validate(false)
|
812
|
-
end
|
813
|
-
|
814
|
-
it 'rejects when the :validate option does not match' do
|
815
|
-
expect(having_one_detail(validate: true)).
|
816
|
-
not_to have_one(:detail).validate(false)
|
817
|
-
end
|
818
|
-
|
819
|
-
it 'assumes validate() means validate(true)' do
|
820
|
-
expect(having_one_detail(validate: false)).
|
821
|
-
not_to have_one(:detail).validate
|
822
|
-
end
|
823
|
-
|
824
|
-
it 'matches validate(false) to having no validate option specified' do
|
825
|
-
expect(having_one_detail).to have_one(:detail).validate(false)
|
826
|
-
end
|
827
|
-
end
|
828
|
-
|
829
|
-
def having_one_detail(options = {})
|
830
|
-
define_model :detail, person_id: :integer
|
831
|
-
define_model(:person).tap do |model|
|
832
|
-
if options.key?(:order)
|
833
|
-
order = options.delete(:order)
|
834
|
-
define_association_with_order(model, :has_one, :detail, order, options)
|
835
|
-
else
|
836
|
-
model.has_one :detail, options
|
837
|
-
end
|
838
|
-
end.new
|
839
|
-
end
|
840
|
-
|
841
|
-
def having_one_non_existent(model_name, assoc_name, options = {})
|
842
|
-
define_model model_name do
|
843
|
-
has_one assoc_name, options
|
844
|
-
end.new
|
845
|
-
end
|
846
|
-
end
|
847
|
-
|
848
|
-
context 'have_and_belong_to_many' do
|
849
|
-
it 'accepts a valid association' do
|
850
|
-
expect(having_and_belonging_to_many_relatives).
|
851
|
-
to have_and_belong_to_many(:relatives)
|
852
|
-
end
|
853
|
-
|
854
|
-
it 'rejects a nonexistent association' do
|
855
|
-
define_model :relative
|
856
|
-
define_model :person
|
857
|
-
define_model :people_relative, id: false, person_id: :integer,
|
858
|
-
relative_id: :integer
|
859
|
-
|
860
|
-
expect(Person.new).not_to have_and_belong_to_many(:relatives)
|
861
|
-
end
|
862
|
-
|
863
|
-
it 'rejects an association with a nonexistent join table' do
|
864
|
-
define_model :relative
|
865
|
-
define_model :person do
|
866
|
-
has_and_belongs_to_many :relatives
|
867
|
-
end
|
868
|
-
|
869
|
-
expected_failure_message = "join table people_relatives doesn't exist"
|
870
|
-
|
871
|
-
expect do
|
872
|
-
expect(Person.new).to have_and_belong_to_many(:relatives)
|
873
|
-
end.to fail_with_message_including(expected_failure_message)
|
874
|
-
end
|
875
|
-
|
876
|
-
it 'rejects an association with a join table with incorrect columns' do
|
877
|
-
define_model :relative
|
878
|
-
define_model :person do
|
879
|
-
has_and_belongs_to_many :relatives
|
880
|
-
end
|
881
|
-
|
882
|
-
define_model :people_relative, id: false, some_crazy_id: :integer
|
883
|
-
|
884
|
-
expect do
|
885
|
-
expect(Person.new).to have_and_belong_to_many(:relatives)
|
886
|
-
end.to fail_with_message_including('missing columns: person_id, relative_id')
|
887
|
-
end
|
888
|
-
|
889
|
-
context 'when the association is declared with a :join_table option' do
|
890
|
-
it 'accepts when testing with the same :join_table option' do
|
891
|
-
join_table_name = 'people_and_their_families'
|
892
|
-
|
893
|
-
define_model :relative
|
894
|
-
|
895
|
-
define_model :person do
|
896
|
-
has_and_belongs_to_many(:relatives, join_table: join_table_name)
|
897
|
-
end
|
898
|
-
|
899
|
-
create_table(join_table_name, id: false) do |t|
|
900
|
-
t.references :person
|
901
|
-
t.references :relative
|
902
|
-
end
|
903
|
-
|
904
|
-
expect(Person.new).
|
905
|
-
to have_and_belong_to_many(:relatives).
|
906
|
-
join_table(join_table_name)
|
907
|
-
end
|
908
|
-
|
909
|
-
it 'accepts even when not explicitly testing with a :join_table option' do
|
910
|
-
join_table_name = 'people_and_their_families'
|
911
|
-
|
912
|
-
define_model :relative
|
913
|
-
|
914
|
-
define_model :person do
|
915
|
-
has_and_belongs_to_many(:relatives,
|
916
|
-
join_table: join_table_name
|
917
|
-
)
|
918
|
-
end
|
919
|
-
|
920
|
-
create_table(join_table_name, id: false) do |t|
|
921
|
-
t.references :person
|
922
|
-
t.references :relative
|
923
|
-
end
|
924
|
-
|
925
|
-
expect(Person.new).to have_and_belong_to_many(:relatives)
|
926
|
-
end
|
927
|
-
|
928
|
-
it 'rejects when testing with a different :join_table option' do
|
929
|
-
join_table_name = 'people_and_their_families'
|
930
|
-
|
931
|
-
define_model :relative
|
932
|
-
|
933
|
-
define_model :person do
|
934
|
-
has_and_belongs_to_many(
|
935
|
-
:relatives,
|
936
|
-
join_table: join_table_name
|
937
|
-
)
|
938
|
-
end
|
939
|
-
|
940
|
-
create_table(join_table_name, id: false) do |t|
|
941
|
-
t.references :person
|
942
|
-
t.references :relative
|
943
|
-
end
|
944
|
-
|
945
|
-
assertion = lambda do
|
946
|
-
expect(Person.new).
|
947
|
-
to have_and_belong_to_many(:relatives).
|
948
|
-
join_table('family_tree')
|
949
|
-
end
|
950
|
-
|
951
|
-
expect(&assertion).to fail_with_message_including(
|
952
|
-
"relatives should use 'family_tree' for :join_table option"
|
953
|
-
)
|
954
|
-
end
|
955
|
-
end
|
956
|
-
|
957
|
-
context 'when the association is not declared with a :join_table option' do
|
958
|
-
it 'rejects when testing with a :join_table option' do
|
959
|
-
define_model :relative
|
960
|
-
|
961
|
-
define_model :person do
|
962
|
-
has_and_belongs_to_many(:relatives)
|
963
|
-
end
|
964
|
-
|
965
|
-
create_table('people_relatives', id: false) do |t|
|
966
|
-
t.references :person
|
967
|
-
t.references :relative
|
968
|
-
end
|
969
|
-
|
970
|
-
assertion = lambda do
|
971
|
-
expect(Person.new).
|
972
|
-
to have_and_belong_to_many(:relatives).
|
973
|
-
join_table('family_tree')
|
974
|
-
end
|
975
|
-
|
976
|
-
expect(&assertion).to fail_with_message_including(
|
977
|
-
"relatives should use 'family_tree' for :join_table option"
|
978
|
-
)
|
979
|
-
end
|
980
|
-
end
|
981
|
-
|
982
|
-
context 'using a custom foreign key' do
|
983
|
-
it 'rejects an association with a join table with incorrect columns' do
|
984
|
-
define_model :relative
|
985
|
-
define_model :person do
|
986
|
-
has_and_belongs_to_many :relatives,
|
987
|
-
foreign_key: :custom_foreign_key_id
|
988
|
-
end
|
989
|
-
|
990
|
-
define_model :people_relative,
|
991
|
-
id: false,
|
992
|
-
custom_foreign_key_id: :integer,
|
993
|
-
some_crazy_id: :integer
|
994
|
-
|
995
|
-
expect do
|
996
|
-
expect(Person.new).to have_and_belong_to_many(:relatives)
|
997
|
-
end.to fail_with_message_including('missing column: relative_id')
|
998
|
-
end
|
999
|
-
end
|
1000
|
-
|
1001
|
-
context 'using a custom association foreign key' do
|
1002
|
-
it 'rejects an association with a join table with incorrect columns' do
|
1003
|
-
define_model :relative
|
1004
|
-
define_model :person do
|
1005
|
-
has_and_belongs_to_many :relatives,
|
1006
|
-
association_foreign_key: :custom_association_foreign_key_id
|
1007
|
-
end
|
1008
|
-
|
1009
|
-
define_model :people_relative,
|
1010
|
-
id: false,
|
1011
|
-
custom_association_foreign_key_id: :integer,
|
1012
|
-
some_crazy_id: :integer
|
1013
|
-
|
1014
|
-
expect do
|
1015
|
-
expect(Person.new).to have_and_belong_to_many(:relatives)
|
1016
|
-
end.to fail_with_message_including('missing column: person_id')
|
1017
|
-
end
|
1018
|
-
|
1019
|
-
it 'accepts foreign keys when they are symbols' do
|
1020
|
-
define_model :relative
|
1021
|
-
define_model :person do
|
1022
|
-
has_and_belongs_to_many :relatives,
|
1023
|
-
foreign_key: :some_foreign_key_id,
|
1024
|
-
association_foreign_key: :custom_association_foreign_key_id
|
1025
|
-
end
|
1026
|
-
|
1027
|
-
define_model :people_relative,
|
1028
|
-
id: false,
|
1029
|
-
custom_association_foreign_key_id: :integer,
|
1030
|
-
some_foreign_key_id: :integer
|
1031
|
-
|
1032
|
-
expect(Person.new).to have_and_belong_to_many(:relatives)
|
1033
|
-
|
1034
|
-
end
|
1035
|
-
|
1036
|
-
end
|
1037
|
-
|
1038
|
-
it 'rejects an association of the wrong type' do
|
1039
|
-
define_model :relative, person_id: :integer
|
1040
|
-
define_model :person do
|
1041
|
-
has_many :relatives
|
1042
|
-
end
|
1043
|
-
|
1044
|
-
expect(Person.new).not_to have_and_belong_to_many(:relatives)
|
1045
|
-
end
|
1046
|
-
|
1047
|
-
it 'accepts an association with a valid :conditions option' do
|
1048
|
-
define_model :relative, adopted: :boolean
|
1049
|
-
define_model(:person).tap do |model|
|
1050
|
-
define_association_with_conditions(model, :has_and_belongs_to_many, :relatives, adopted: true)
|
1051
|
-
end
|
1052
|
-
define_model :people_relative, id: false, person_id: :integer,
|
1053
|
-
relative_id: :integer
|
1054
|
-
|
1055
|
-
expect(Person.new).to have_and_belong_to_many(:relatives).conditions(adopted: true)
|
1056
|
-
end
|
1057
|
-
|
1058
|
-
it 'rejects an association with a bad :conditions option' do
|
1059
|
-
define_model :relative, adopted: :boolean
|
1060
|
-
define_model :person do
|
1061
|
-
has_and_belongs_to_many :relatives
|
1062
|
-
end
|
1063
|
-
define_model :people_relative, id: false, person_id: :integer,
|
1064
|
-
relative_id: :integer
|
1065
|
-
|
1066
|
-
expect(Person.new).not_to have_and_belong_to_many(:relatives).conditions(adopted: true)
|
1067
|
-
end
|
1068
|
-
|
1069
|
-
it 'accepts an association without a :class_name option' do
|
1070
|
-
expect(having_and_belonging_to_many_relatives).
|
1071
|
-
to have_and_belong_to_many(:relatives).class_name('Relative')
|
1072
|
-
end
|
1073
|
-
|
1074
|
-
it 'accepts an association with a valid :class_name option' do
|
1075
|
-
define_model :person_relative, adopted: :boolean
|
1076
|
-
define_model :person do
|
1077
|
-
has_and_belongs_to_many :relatives, class_name: 'PersonRelative'
|
1078
|
-
end
|
1079
|
-
|
1080
|
-
define_model :people_person_relative, person_id: :integer,
|
1081
|
-
person_relative_id: :integer
|
1082
|
-
|
1083
|
-
expect(Person.new).to have_and_belong_to_many(:relatives).class_name('PersonRelative')
|
1084
|
-
end
|
1085
|
-
|
1086
|
-
it 'rejects an association with a bad :class_name option' do
|
1087
|
-
expect(having_and_belonging_to_many_relatives).
|
1088
|
-
not_to have_and_belong_to_many(:relatives).class_name('PersonRelatives')
|
1089
|
-
end
|
1090
|
-
|
1091
|
-
it 'rejects an association with non-existent implicit class name' do
|
1092
|
-
expect(having_and_belonging_to_many_non_existent_class(:person, :relatives)).
|
1093
|
-
not_to have_and_belong_to_many(:relatives)
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
it 'rejects an association with non-existent explicit class name' do
|
1097
|
-
expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative')).
|
1098
|
-
not_to have_and_belong_to_many(:relatives)
|
1099
|
-
end
|
1100
|
-
|
1101
|
-
it 'adds error message when rejecting an association with non-existent class' do
|
1102
|
-
message = 'Expected Person to have a has_and_belongs_to_many association called relatives (Relative2 does not exist)'
|
1103
|
-
expect {
|
1104
|
-
expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative2')).
|
1105
|
-
to have_and_belong_to_many(:relatives)
|
1106
|
-
}.to fail_with_message(message)
|
1107
|
-
end
|
1108
|
-
|
1109
|
-
it 'accepts an association with a namespaced class name' do
|
1110
|
-
possible_join_table_names = [:groups_users, :models_groups_users, :groups_models_users]
|
1111
|
-
possible_join_table_names.each do |join_table_name|
|
1112
|
-
create_table join_table_name, id: false do |t|
|
1113
|
-
t.integer :group_id
|
1114
|
-
t.integer :user_id
|
1115
|
-
end
|
1116
|
-
end
|
1117
|
-
define_module 'Models'
|
1118
|
-
define_model 'Models::Group'
|
1119
|
-
user_model = define_model 'Models::User' do
|
1120
|
-
has_and_belongs_to_many :groups, class_name: 'Group'
|
1121
|
-
end
|
1122
|
-
|
1123
|
-
expect(user_model.new).
|
1124
|
-
to have_and_belong_to_many(:groups).
|
1125
|
-
class_name('Group')
|
1126
|
-
end
|
1127
|
-
|
1128
|
-
it 'resolves class_name within the context of the namespace before the global namespace' do
|
1129
|
-
possible_join_table_names = [:groups_users, :models_groups_users, :groups_models_users]
|
1130
|
-
possible_join_table_names.each do |join_table_name|
|
1131
|
-
create_table join_table_name, id: false do |t|
|
1132
|
-
t.integer :group_id
|
1133
|
-
t.integer :user_id
|
1134
|
-
end
|
1135
|
-
end
|
1136
|
-
define_module 'Models'
|
1137
|
-
define_model 'Group'
|
1138
|
-
define_model 'Models::Group'
|
1139
|
-
user_model = define_model 'Models::User' do
|
1140
|
-
has_and_belongs_to_many :groups, class_name: 'Group'
|
1141
|
-
end
|
1142
|
-
|
1143
|
-
expect(user_model.new).
|
1144
|
-
to have_and_belong_to_many(:groups).
|
1145
|
-
class_name('Group')
|
1146
|
-
end
|
1147
|
-
|
1148
|
-
it 'accepts an association with a matching :autosave option' do
|
1149
|
-
define_model :relatives, adopted: :boolean
|
1150
|
-
define_model :person do
|
1151
|
-
has_and_belongs_to_many :relatives, autosave: true
|
1152
|
-
end
|
1153
|
-
define_model :people_relative, person_id: :integer,
|
1154
|
-
relative_id: :integer
|
1155
|
-
expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
|
1156
|
-
end
|
1157
|
-
|
1158
|
-
it 'rejects an association with a non-matching :autosave option with the correct message' do
|
1159
|
-
define_model :relatives, adopted: :boolean
|
1160
|
-
define_model :person do
|
1161
|
-
has_and_belongs_to_many :relatives
|
1162
|
-
end
|
1163
|
-
define_model :people_relative, person_id: :integer,
|
1164
|
-
relative_id: :integer
|
1165
|
-
|
1166
|
-
message = 'Expected Person to have a has_and_belongs_to_many association called relatives (relatives should have autosave set to true)'
|
1167
|
-
expect {
|
1168
|
-
expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
|
1169
|
-
}.to fail_with_message(message)
|
1170
|
-
end
|
1171
|
-
|
1172
|
-
context 'validate' do
|
1173
|
-
it 'accepts when the :validate option matches' do
|
1174
|
-
expect(having_and_belonging_to_many_relatives(validate: false)).
|
1175
|
-
to have_and_belong_to_many(:relatives).validate(false)
|
1176
|
-
end
|
1177
|
-
|
1178
|
-
it 'rejects when the :validate option does not match' do
|
1179
|
-
expect(having_and_belonging_to_many_relatives(validate: true)).
|
1180
|
-
to have_and_belong_to_many(:relatives).validate(false)
|
1181
|
-
end
|
1182
|
-
|
1183
|
-
it 'assumes validate() means validate(true)' do
|
1184
|
-
expect(having_and_belonging_to_many_relatives(validate: false)).
|
1185
|
-
not_to have_and_belong_to_many(:relatives).validate
|
1186
|
-
end
|
1187
|
-
|
1188
|
-
it 'matches validate(false) to having no validate option specified' do
|
1189
|
-
expect(having_and_belonging_to_many_relatives).
|
1190
|
-
to have_and_belong_to_many(:relatives).validate(false)
|
1191
|
-
end
|
1192
|
-
end
|
1193
|
-
|
1194
|
-
def having_and_belonging_to_many_relatives(options = {})
|
1195
|
-
define_model :relative
|
1196
|
-
define_model :people_relative, id: false, person_id: :integer,
|
1197
|
-
relative_id: :integer
|
1198
|
-
define_model :person do
|
1199
|
-
has_and_belongs_to_many :relatives
|
1200
|
-
end.new
|
1201
|
-
end
|
1202
|
-
|
1203
|
-
def having_and_belonging_to_many_non_existent_class(model_name, assoc_name, options = {})
|
1204
|
-
define_model model_name do
|
1205
|
-
has_and_belongs_to_many assoc_name, options
|
1206
|
-
end.new
|
1207
|
-
end
|
1208
|
-
end
|
1209
|
-
|
1210
|
-
def define_association_with_conditions(model, macro, name, conditions, other_options={})
|
1211
|
-
args = []
|
1212
|
-
options = {}
|
1213
|
-
if Shoulda::Matchers::RailsShim.active_record_major_version == 4
|
1214
|
-
args << proc { where(conditions) }
|
1215
|
-
else
|
1216
|
-
options[:conditions] = conditions
|
1217
|
-
end
|
1218
|
-
args << options
|
1219
|
-
model.__send__(macro, name, *args)
|
1220
|
-
end
|
1221
|
-
|
1222
|
-
def define_association_with_order(model, macro, name, order, other_options={})
|
1223
|
-
args = []
|
1224
|
-
options = {}
|
1225
|
-
if Shoulda::Matchers::RailsShim.active_record_major_version == 4
|
1226
|
-
args << proc { order(order) }
|
1227
|
-
else
|
1228
|
-
options[:order] = order
|
1229
|
-
end
|
1230
|
-
args << options
|
1231
|
-
model.__send__(macro, name, *args)
|
1232
|
-
end
|
1233
|
-
|
1234
|
-
def dependent_options
|
1235
|
-
case Rails.version
|
1236
|
-
when /\A3/
|
1237
|
-
[:destroy, :delete, :nullify, :restrict]
|
1238
|
-
when /\A4/
|
1239
|
-
[:destroy, :delete, :nullify, :restrict_with_exception, :restrict_with_error]
|
1240
|
-
end
|
1241
|
-
end
|
1242
|
-
end
|