From 2e1777cde96dab0184527a3b230ce8704154590e Mon Sep 17 00:00:00 2001 From: John Small Date: Fri, 3 Mar 2017 10:17:07 +0000 Subject: [PATCH 1/2] fixed the test for has_one without included data, and the code that makes the test pass --- lib/json_api_client/associations/has_one.rb | 2 +- lib/json_api_client/included_data.rb | 27 +++++++++------------ lib/json_api_client/resource.rb | 15 +++++++++--- test/unit/association_test.rb | 16 +++++++----- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/lib/json_api_client/associations/has_one.rb b/lib/json_api_client/associations/has_one.rb index 20edc533..c0a91378 100644 --- a/lib/json_api_client/associations/has_one.rb +++ b/lib/json_api_client/associations/has_one.rb @@ -16,4 +16,4 @@ def from_result_set(result_set) end end end -end \ No newline at end of file +end diff --git a/lib/json_api_client/included_data.rb b/lib/json_api_client/included_data.rb index 2ae26591..207ed83b 100644 --- a/lib/json_api_client/included_data.rb +++ b/lib/json_api_client/included_data.rb @@ -18,17 +18,20 @@ def initialize(result_set, data) end def data_for(method_name, definition) + # this method only returns an array. It's up to the caller to decide if it's going to return + # just the first element if it's a has_one relationship. # If data is defined, pull the record from the included data - return nil unless data = definition["data"] - - if data.is_a?(Array) - # has_many link - data.map do |link_def| - record_for(link_def) + defined_data = definition["data"] + return nil unless defined_data + [defined_data].flatten.map do |link_def| + # should return a resource record of some type for this linked document + # even if there's no matching record included. + if data[link_def["type"]] + data[link_def["type"]][link_def["id"]] + else + # if there's no matching record in included then go and get it given the data + link_def["type"].classify.constantize.find(link_def["id"]).first end - else - # has_one link - record_for(data) end end @@ -36,11 +39,5 @@ def has_link?(name) data.has_key?(name.to_s) end - private - - # should return a resource record of some type for this linked document - def record_for(link_def) - data[link_def["type"]][link_def["id"]] - end end end diff --git a/lib/json_api_client/resource.rb b/lib/json_api_client/resource.rb index 8a2b0d4c..1e348984 100644 --- a/lib/json_api_client/resource.rb +++ b/lib/json_api_client/resource.rb @@ -448,10 +448,17 @@ def method_missing(method, *args) return nil unless relationship_definitions = relationships[method] # look in included data - if relationship_definitions.key?("data") - return last_result_set.included.data_for(method, relationship_definitions) - end - + if relationship_definitions.key?("data") + # included.data_for returns an array, if the association is a has_one, then pick the first, otherise return the whole array + if association.is_a?(JsonApiClient::Associations::HasOne::Association) + return last_result_set.included.data_for(method, relationship_definitions).try(:first) + else + return last_result_set.included.data_for(method, relationship_definitions) + end + end + + # I'm very puzzled by this as we have association = association_for(method) in the first line of this method + # is it intened to be 'if association == association_for(method)' if association = association_for(method) # look for a defined relationship url if relationship_definitions["links"] && url = relationship_definitions["links"]["related"] diff --git a/test/unit/association_test.rb b/test/unit/association_test.rb index a370d450..0690fb8b 100644 --- a/test/unit/association_test.rb +++ b/test/unit/association_test.rb @@ -33,7 +33,7 @@ class Property < TestResource class AssociationTest < MiniTest::Test - def test_load_has_one + def test_load_has_one_without_include stub_request(:get, "http://example.com/properties/1") .to_return(headers: {content_type: "application/vnd.api+json"}, body: { data: [ @@ -48,17 +48,20 @@ def test_load_has_one } } } - ], - included: [ + ] + + }.to_json) + stub_request(:get, "http://example.com/owners/1") + .to_return(headers: {content_type: "application/vnd.api+json"}, body: { + data: [ { id: 1, - type: 'owner', + type: "owner", attributes: { - name: 'Jeff Ching' + name: "Jeff Ching" } } ] - }.to_json) property = Property.find(1).first assert_equal(Owner, property.owner.class) @@ -96,6 +99,7 @@ def test_load_has_one_with_include }.to_json) property = Property.includes(:owner).find(1).first + assert_equal(Owner, property.owner.class) assert_equal("Jeff Ching", property.owner.name) end From 2c94d0e77e336aadf6fc9ea6c0ca916e76785b03 Mon Sep 17 00:00:00 2001 From: John Small Date: Mon, 6 Mar 2017 10:12:36 +0000 Subject: [PATCH 2/2] whoops missed out underscore when translating types into model constants --- lib/json_api_client/included_data.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/json_api_client/included_data.rb b/lib/json_api_client/included_data.rb index 207ed83b..aca22ada 100644 --- a/lib/json_api_client/included_data.rb +++ b/lib/json_api_client/included_data.rb @@ -30,7 +30,7 @@ def data_for(method_name, definition) data[link_def["type"]][link_def["id"]] else # if there's no matching record in included then go and get it given the data - link_def["type"].classify.constantize.find(link_def["id"]).first + link_def["type"].underscore.classify.constantize.find(link_def["id"]).first end end end