diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b841cc..299da97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- [#403](https://github.com/JsonApiClient/json_api_client/pull/403) - Feature: Use the association options to lookup relationship class - [#406](https://github.com/JsonApiClient/json_api_client/pull/406) - Deep-merge nested `additional_params` ## 1.21.1 diff --git a/lib/json_api_client/utils.rb b/lib/json_api_client/utils.rb index e91e566..121550d 100644 --- a/lib/json_api_client/utils.rb +++ b/lib/json_api_client/utils.rb @@ -7,6 +7,11 @@ def self.compute_type(klass, type_name) # the type_name is an absolute reference. return type_name.constantize if type_name.match(/^::/) + # Check the klass association definitions + association_klass_match = klass.associations.find { |a| a.attr_name.to_s.singularize == type_name.underscore } + association_klass = association_klass_match.options[:class] if association_klass_match + return association_klass if association_klass + # Build a list of candidates to search for candidates = [] klass.name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" } diff --git a/test/unit/association_test.rb b/test/unit/association_test.rb index 24ce3db..a81dd7d 100644 --- a/test/unit/association_test.rb +++ b/test/unit/association_test.rb @@ -89,8 +89,21 @@ class Employee < TestResource has_one :chief, klass: 'Employee' end -class AssociationTest < Minitest::Test +module CrossNamespaceTwo + class Nail < TestResource + property :size + end +end + +module CrossNamespaceOne + class Hammer < TestResource + property :brand + has_many :nails, class: CrossNamespaceTwo::Nail + end +end + +class AssociationTest < Minitest::Test def test_default_properties_no_changes stub_request(:post, 'http://example.com/accounts'). with(headers: { content_type: 'application/vnd.api+json', accept: 'application/vnd.api+json' }, body: { @@ -1070,4 +1083,62 @@ def test_does_not_load_include_from_dataset assert_nil(records.first.chief) end + def test_cross_namespace_resource_references + stub_request(:get, 'http://example.com/hammers?include=nails') + .to_return( + headers: { + content_type: 'application/vnd.api+json' + }, body: { + data: [ + { + id: '1', + type: 'hammers', + attributes: { + brand: 'Hardware Store' + }, + relationships: { + nails: { data: [{id: '2', type: 'nails'}] } + } + }, + { + id: '2', + type: 'hammers', + attributes: { + brand: 'Hardware Store' + }, + relationships: { + nails: { data: [{id: '3', type: 'nails'}] } + } + } + ], + included: [ + { + id: '2', + type: 'nails', + attributes: { + size: 10 + } + }, + { + id: '3', + type: 'nails', + attributes: { + size: 8 + } + } + ] + }.to_json) + + records = CrossNamespaceOne::Hammer.includes(:nails).to_a + + assert_equal(2, records.size) + assert_equal('1', records.first.id) + assert_equal('2', records.second.id) + assert_equal('2', records.first.nails.first.id) + assert_equal('3', records.second.nails.first.id) + + assert_equal(1, records.first.nails.size) + assert_equal(1, records.second.nails.size) + end + end