From e67d6764e4f04e165a8b20214869f6684581bace Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Sun, 31 Dec 2023 17:14:23 +0530 Subject: [PATCH 1/8] fix: more flexible polymorphic types lookup --- lib/jsonapi/relationship.rb | 2 +- lib/jsonapi/utils/polymorphic_types_lookup.rb | 29 +++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/lib/jsonapi/relationship.rb b/lib/jsonapi/relationship.rb index bff416da..1378d8e7 100644 --- a/lib/jsonapi/relationship.rb +++ b/lib/jsonapi/relationship.rb @@ -193,7 +193,7 @@ def polymorphic_type def setup_implicit_relationships_for_polymorphic_types(exclude_linkage_data: true) types = self.class.polymorphic_types(_relation_name) unless types.present? - warn "No polymorphic types found for #{parent_resource.name} #{_relation_name}" + warn "[POLYMORPHIC TYPE] No polymorphic types found for #{parent_resource.name} #{_relation_name}" return end diff --git a/lib/jsonapi/utils/polymorphic_types_lookup.rb b/lib/jsonapi/utils/polymorphic_types_lookup.rb index 2a72673e..11732ebb 100644 --- a/lib/jsonapi/utils/polymorphic_types_lookup.rb +++ b/lib/jsonapi/utils/polymorphic_types_lookup.rb @@ -6,7 +6,16 @@ module PolymorphicTypesLookup extend self def polymorphic_types(name) - polymorphic_types_lookup[name.to_sym] + polymorphic_types_lookup.fetch(name.to_sym) do + klass = name.classify.safe_constantize + if klass.nil? + warn "[POLYMORPHIC TYPE NOT FOUND] No polymorphic types found for #{name}" + else + polymorphic_type = format_polymorphic_klass_type(klass) + warn "[POLYMORPHIC TYPE] Found polymorphic types through reflection for #{name}: #{polymorphic_type}" + polymorphic_types_lookup[name.to_sym] = [polymorphic_type] + end + end end def polymorphic_types_lookup @@ -17,14 +26,28 @@ def build_polymorphic_types_lookup {}.tap do |hash| ObjectSpace.each_object do |klass| next unless Module === klass - if ActiveRecord::Base > klass + is_active_record_inspectable = ActiveRecord::Base > klass + is_active_record_inspectable &&= klass.respond_to?(:reflect_on_all_associations, true) + is_active_record_inspectable &&= format_polymorphic_klass_type(klass).present? + if is_active_record_inspectable klass.reflect_on_all_associations(:has_many).select { |r| r.options[:as] }.each do |reflection| - (hash[reflection.options[:as]] ||= []) << klass.name.underscore + (hash[reflection.options[:as]] ||= []) << format_polymorphic_klass_type(klass).underscore end end end end end + + def format_polymorphic_klass_type(klass) + klass.name || + begin + klass.model_name.name + rescue ArgumentError => ex + # klass.base_class may be nil + warn "[POLYMORPHIC TYPE] #{__callee__} #{klass} #{ex.inspect}" + nil + end + end end end end From d14cbad2ad6a24955c1184f7af641c43edf88e9f Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 17 Jan 2024 01:45:46 -0600 Subject: [PATCH 2/8] test: add polymorphic lookup tests they pass on v-11-dev I'm going to look into the existing lookup warnings now ``` [POLYMORPHIC TYPE NOT FOUND] No polymorphic types found for fileable [POLYMORPHIC TYPE] No polymorphic types found for FilePropertiesResource fileable [POLYMORPHIC TYPE NOT FOUND] No polymorphic types found for respondent [POLYMORPHIC TYPE] No polymorphic types found for QuestionResource respondent [POLYMORPHIC TYPE NOT FOUND] No polymorphic types found for respondent [POLYMORPHIC TYPE] No polymorphic types found for AnswerResource respondent [POLYMORPHIC TYPE NOT FOUND] No polymorphic types found for keepable [POLYMORPHIC TYPE] No polymorphic types found for KeeperResource keepable ``` --- test/fixtures/active_record.rb | 60 ++++++++++++++ test/integration/requests/polymorphic_test.rb | 83 +++++++++++++++++++ test/test_helper.rb | 3 + 3 files changed, 146 insertions(+) create mode 100644 test/integration/requests/polymorphic_test.rb diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index 92281e2a..5902e939 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -430,6 +430,18 @@ t.integer :version t.timestamps null: false end + create_table :contact_media do |t| + t.string :name + t.references :party, polymorphic: true, index: true + end + + create_table :individuals do |t| + t.string :name + end + + create_table :organizations do |t| + t.string :name + end end ### MODELS @@ -625,6 +637,24 @@ class Fact < ActiveRecord::Base class Like < ActiveRecord::Base end +class TestApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end + +class ContactMedium < TestApplicationRecord + belongs_to :party, polymorphic: true, inverse_of: :contact_media + belongs_to :individual, -> { where( contact_media: { party_type: 'Individual' } ).eager_load( :contact_media ) }, foreign_key: 'party_id' + belongs_to :organization, -> { where( contact_media: { party_type: 'Organization' } ).eager_load( :contact_media ) }, foreign_key: 'party_id' +end + +class Individual < TestApplicationRecord + has_many :contact_media, as: :party +end + +class Organization < TestApplicationRecord + has_many :contact_media, as: :party +end + class Breed include ActiveModel::Model @@ -1231,6 +1261,18 @@ class IndicatorsController < JSONAPI::ResourceController class RobotsController < JSONAPI::ResourceController end +class IndividualsController < BaseController +end + +class OrganizationsController < BaseController +end + +class ContactMediaController < BaseController +end + +class PartiesController < BaseController +end + ### RESOURCES class BaseResource < JSONAPI::Resource abstract @@ -2692,6 +2734,24 @@ class RobotResource < ::JSONAPI::Resource end end +class ContactMediumResource < JSONAPI::Resource + attribute :name + has_one :party, polymorphic: true +end + +class IndividualResource < JSONAPI::Resource + attribute :name + has_many :contact_media +end + +class OrganizationResource < JSONAPI::Resource + attribute :name + has_many :contact_media +end + +class PartyResource < JSONAPI::Resource +end + ### PORO Data - don't do this in a production app $breed_data = BreedData.new $breed_data.add(Breed.new(0, 'persian')) diff --git a/test/integration/requests/polymorphic_test.rb b/test/integration/requests/polymorphic_test.rb new file mode 100644 index 00000000..c259e030 --- /dev/null +++ b/test/integration/requests/polymorphic_test.rb @@ -0,0 +1,83 @@ +require File.expand_path('../../../test_helper', __FILE__) + +# copied from https://github.com/cerebris/jsonapi-resources/blob/e60dc7dd2c7fdc85834163a7e706a10a8940a62b/test/integration/requests/polymorphic_test.rb +# https://github.com/cerebris/jsonapi-resources/compare/bf4_fix_polymorphic_relations_lookup?expand=1 +class PolymorphicTest < ActionDispatch::IntegrationTest + + def json_api_headers + {'Accept' => JSONAPI::MEDIA_TYPE, 'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE} + end + + def test_find_party_via_contact_medium + individual = Individual.create(name: 'test') + contact_medium = ContactMedium.create(party: individual, name: 'test contact medium') + fetched_party = contact_medium.party + assert_same individual, fetched_party, "Expect an individual to have been found via contact medium model's relationship 'party'" + end + + def test_get_individual + individual = Individual.create(name: 'test') + ContactMedium.create(party: individual, name: 'test contact medium') + get "/individuals/#{individual.id}" + assert_jsonapi_response 200 + end + + def test_get_party_via_contact_medium + individual = Individual.create(name: 'test') + contact_medium = ContactMedium.create(party: individual, name: 'test contact medium') + get "/contact_media/#{contact_medium.id}/party" + assert_jsonapi_response 200, "Expect an individual to have been found via contact medium resource's relationship 'party'" + end +end + +# copied from https://github.com/cerebris/jsonapi-resources/pull/1349/files +# require File.expand_path('../test_helper', __FILE__) +# +# Replace this with the code necessary to make your test fail. +# class BugTest < Minitest::Test +# include Rack::Test::Methods +# +# def json_api_headers +# {'Accept' => JSONAPI::MEDIA_TYPE, 'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE} +# end +# +# def teardown +# Individual.delete_all +# ContactMedium.delete_all +# end +# +# def test_find_party_via_contact_medium +# individual = Individual.create(name: 'test') +# contact_medium = ContactMedium.create(party: individual, name: 'test contact medium') +# fetched_party = contact_medium.party +# assert_same individual, fetched_party, "Expect an individual to have been found via contact medium model's relationship 'party'" +# end +# +# def test_get_individual +# individual = Individual.create(name: 'test') +# ContactMedium.create(party: individual, name: 'test contact medium') +# get "/individuals/#{individual.id}" +# assert_last_response_status 200 +# end +# +# def test_get_party_via_contact_medium +# individual = Individual.create(name: 'test') +# contact_medium = ContactMedium.create(party: individual, name: 'test contact medium') +# get "/contact_media/#{contact_medium.id}/party" +# assert_last_response_status 200, "Expect an individual to have been found via contact medium resource's relationship 'party'" +# end +# +# private +# +# def assert_last_response_status(status, failure_reason=nil) +# if last_response.status != status +# json_response = JSON.parse(last_response.body) rescue last_response.body +# pp json_response +# end +# assert_equal status, last_response.status, failure_reason +# end +# +# def app +# Rails.application +# end +# end diff --git a/test/test_helper.rb b/test/test_helper.rb index 9f8f03b2..8c0353dc 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -420,6 +420,9 @@ class CatResource < JSONAPI::Resource jsonapi_resources :widgets, only: [:index] jsonapi_resources :indicators, only: [:index] jsonapi_resources :robots, only: [:index] + jsonapi_resources :contact_media + jsonapi_resources :individuals + jsonapi_resources :organizations mount MyEngine::Engine => "/boomshaka", as: :my_engine mount ApiV2Engine::Engine => "/api_v2", as: :api_v2_engine From 221244b4b9178799b4f910f41539c523b6a8295b Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Mon, 22 Jan 2024 20:41:41 -0600 Subject: [PATCH 3/8] Revert "test: add polymorphic lookup tests" This reverts commit 0979a7243b6bc816dd2327d3ff23f70209c52dce. --- test/fixtures/active_record.rb | 60 -------------- test/integration/requests/polymorphic_test.rb | 83 ------------------- test/test_helper.rb | 3 - 3 files changed, 146 deletions(-) delete mode 100644 test/integration/requests/polymorphic_test.rb diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index 5902e939..92281e2a 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -430,18 +430,6 @@ t.integer :version t.timestamps null: false end - create_table :contact_media do |t| - t.string :name - t.references :party, polymorphic: true, index: true - end - - create_table :individuals do |t| - t.string :name - end - - create_table :organizations do |t| - t.string :name - end end ### MODELS @@ -637,24 +625,6 @@ class Fact < ActiveRecord::Base class Like < ActiveRecord::Base end -class TestApplicationRecord < ActiveRecord::Base - self.abstract_class = true -end - -class ContactMedium < TestApplicationRecord - belongs_to :party, polymorphic: true, inverse_of: :contact_media - belongs_to :individual, -> { where( contact_media: { party_type: 'Individual' } ).eager_load( :contact_media ) }, foreign_key: 'party_id' - belongs_to :organization, -> { where( contact_media: { party_type: 'Organization' } ).eager_load( :contact_media ) }, foreign_key: 'party_id' -end - -class Individual < TestApplicationRecord - has_many :contact_media, as: :party -end - -class Organization < TestApplicationRecord - has_many :contact_media, as: :party -end - class Breed include ActiveModel::Model @@ -1261,18 +1231,6 @@ class IndicatorsController < JSONAPI::ResourceController class RobotsController < JSONAPI::ResourceController end -class IndividualsController < BaseController -end - -class OrganizationsController < BaseController -end - -class ContactMediaController < BaseController -end - -class PartiesController < BaseController -end - ### RESOURCES class BaseResource < JSONAPI::Resource abstract @@ -2734,24 +2692,6 @@ class RobotResource < ::JSONAPI::Resource end end -class ContactMediumResource < JSONAPI::Resource - attribute :name - has_one :party, polymorphic: true -end - -class IndividualResource < JSONAPI::Resource - attribute :name - has_many :contact_media -end - -class OrganizationResource < JSONAPI::Resource - attribute :name - has_many :contact_media -end - -class PartyResource < JSONAPI::Resource -end - ### PORO Data - don't do this in a production app $breed_data = BreedData.new $breed_data.add(Breed.new(0, 'persian')) diff --git a/test/integration/requests/polymorphic_test.rb b/test/integration/requests/polymorphic_test.rb deleted file mode 100644 index c259e030..00000000 --- a/test/integration/requests/polymorphic_test.rb +++ /dev/null @@ -1,83 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -# copied from https://github.com/cerebris/jsonapi-resources/blob/e60dc7dd2c7fdc85834163a7e706a10a8940a62b/test/integration/requests/polymorphic_test.rb -# https://github.com/cerebris/jsonapi-resources/compare/bf4_fix_polymorphic_relations_lookup?expand=1 -class PolymorphicTest < ActionDispatch::IntegrationTest - - def json_api_headers - {'Accept' => JSONAPI::MEDIA_TYPE, 'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE} - end - - def test_find_party_via_contact_medium - individual = Individual.create(name: 'test') - contact_medium = ContactMedium.create(party: individual, name: 'test contact medium') - fetched_party = contact_medium.party - assert_same individual, fetched_party, "Expect an individual to have been found via contact medium model's relationship 'party'" - end - - def test_get_individual - individual = Individual.create(name: 'test') - ContactMedium.create(party: individual, name: 'test contact medium') - get "/individuals/#{individual.id}" - assert_jsonapi_response 200 - end - - def test_get_party_via_contact_medium - individual = Individual.create(name: 'test') - contact_medium = ContactMedium.create(party: individual, name: 'test contact medium') - get "/contact_media/#{contact_medium.id}/party" - assert_jsonapi_response 200, "Expect an individual to have been found via contact medium resource's relationship 'party'" - end -end - -# copied from https://github.com/cerebris/jsonapi-resources/pull/1349/files -# require File.expand_path('../test_helper', __FILE__) -# -# Replace this with the code necessary to make your test fail. -# class BugTest < Minitest::Test -# include Rack::Test::Methods -# -# def json_api_headers -# {'Accept' => JSONAPI::MEDIA_TYPE, 'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE} -# end -# -# def teardown -# Individual.delete_all -# ContactMedium.delete_all -# end -# -# def test_find_party_via_contact_medium -# individual = Individual.create(name: 'test') -# contact_medium = ContactMedium.create(party: individual, name: 'test contact medium') -# fetched_party = contact_medium.party -# assert_same individual, fetched_party, "Expect an individual to have been found via contact medium model's relationship 'party'" -# end -# -# def test_get_individual -# individual = Individual.create(name: 'test') -# ContactMedium.create(party: individual, name: 'test contact medium') -# get "/individuals/#{individual.id}" -# assert_last_response_status 200 -# end -# -# def test_get_party_via_contact_medium -# individual = Individual.create(name: 'test') -# contact_medium = ContactMedium.create(party: individual, name: 'test contact medium') -# get "/contact_media/#{contact_medium.id}/party" -# assert_last_response_status 200, "Expect an individual to have been found via contact medium resource's relationship 'party'" -# end -# -# private -# -# def assert_last_response_status(status, failure_reason=nil) -# if last_response.status != status -# json_response = JSON.parse(last_response.body) rescue last_response.body -# pp json_response -# end -# assert_equal status, last_response.status, failure_reason -# end -# -# def app -# Rails.application -# end -# end diff --git a/test/test_helper.rb b/test/test_helper.rb index 8c0353dc..9f8f03b2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -420,9 +420,6 @@ class CatResource < JSONAPI::Resource jsonapi_resources :widgets, only: [:index] jsonapi_resources :indicators, only: [:index] jsonapi_resources :robots, only: [:index] - jsonapi_resources :contact_media - jsonapi_resources :individuals - jsonapi_resources :organizations mount MyEngine::Engine => "/boomshaka", as: :my_engine mount ApiV2Engine::Engine => "/api_v2", as: :api_v2_engine From 658f2bbbdc3745cfbd31f90157eefd236896b1a6 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 24 Jan 2024 08:41:38 -0600 Subject: [PATCH 4/8] feat: easily clear the lookup --- lib/jsonapi/utils/polymorphic_types_lookup.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/jsonapi/utils/polymorphic_types_lookup.rb b/lib/jsonapi/utils/polymorphic_types_lookup.rb index 11732ebb..4ca722e3 100644 --- a/lib/jsonapi/utils/polymorphic_types_lookup.rb +++ b/lib/jsonapi/utils/polymorphic_types_lookup.rb @@ -5,8 +5,8 @@ module Utils module PolymorphicTypesLookup extend self - def polymorphic_types(name) - polymorphic_types_lookup.fetch(name.to_sym) do + def polymorphic_types(name, rebuild: false) + polymorphic_types_lookup(rebuild: rebuild).fetch(name.to_sym) do klass = name.classify.safe_constantize if klass.nil? warn "[POLYMORPHIC TYPE NOT FOUND] No polymorphic types found for #{name}" @@ -18,10 +18,15 @@ def polymorphic_types(name) end end - def polymorphic_types_lookup + def polymorphic_types_lookup(rebuild: false) + polymorphic_types_lookup_clear! if rebuild @polymorphic_types_lookup ||= build_polymorphic_types_lookup end + def polymorphic_types_lookup_clear! + @polymorphic_types_lookup = nil + end + def build_polymorphic_types_lookup {}.tap do |hash| ObjectSpace.each_object do |klass| From 5bec2e0b8659e6566da36058f2f8a143e79623df Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 24 Jan 2024 08:45:22 -0600 Subject: [PATCH 5/8] feat: add a descendents strategy --- lib/jsonapi/utils/polymorphic_types_lookup.rb | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/jsonapi/utils/polymorphic_types_lookup.rb b/lib/jsonapi/utils/polymorphic_types_lookup.rb index 4ca722e3..76b79bb7 100644 --- a/lib/jsonapi/utils/polymorphic_types_lookup.rb +++ b/lib/jsonapi/utils/polymorphic_types_lookup.rb @@ -28,21 +28,45 @@ def polymorphic_types_lookup_clear! end def build_polymorphic_types_lookup - {}.tap do |hash| + public_send(build_polymorphic_types_lookup_strategy) + end + + def build_polymorphic_types_lookup_strategy + :build_polymorphic_types_lookup_from_object_space + end + + def build_polymorphic_types_lookup_from_descendants + {}.tap do |lookup| + ActiveRecord::Base + .descendants + .select(&:name) + .reject(&:abstract_class) + .select(&:model_name).map {|klass| + add_polymorphic_types_lookup(klass: klass, lookup: lookup) + } + end + end + + def build_polymorphic_types_lookup_from_object_space + {}.tap do |lookup| ObjectSpace.each_object do |klass| next unless Module === klass is_active_record_inspectable = ActiveRecord::Base > klass is_active_record_inspectable &&= klass.respond_to?(:reflect_on_all_associations, true) is_active_record_inspectable &&= format_polymorphic_klass_type(klass).present? if is_active_record_inspectable - klass.reflect_on_all_associations(:has_many).select { |r| r.options[:as] }.each do |reflection| - (hash[reflection.options[:as]] ||= []) << format_polymorphic_klass_type(klass).underscore - end + add_polymorphic_types_lookup(klass: klass, lookup: lookup) end end end end + def add_polymorphic_types_lookup(klass:, lookup:) + klass.reflect_on_all_associations(:has_many).select { |r| r.options[:as] }.each do |reflection| + (lookup[reflection.options[:as]] ||= []) << format_polymorphic_klass_type(klass).underscore + end + end + def format_polymorphic_klass_type(klass) klass.name || begin From 7946f835e3548a011276aa4f026c5334192414f9 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 24 Jan 2024 09:10:08 -0600 Subject: [PATCH 6/8] test: polymorphic type lookup --- lib/jsonapi/utils/polymorphic_types_lookup.rb | 47 ++++++++++--------- .../utils/polymorphic_types_lookup_test.rb | 35 ++++++++++++++ 2 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 test/unit/utils/polymorphic_types_lookup_test.rb diff --git a/lib/jsonapi/utils/polymorphic_types_lookup.rb b/lib/jsonapi/utils/polymorphic_types_lookup.rb index 76b79bb7..219349d8 100644 --- a/lib/jsonapi/utils/polymorphic_types_lookup.rb +++ b/lib/jsonapi/utils/polymorphic_types_lookup.rb @@ -6,15 +6,13 @@ module PolymorphicTypesLookup extend self def polymorphic_types(name, rebuild: false) - polymorphic_types_lookup(rebuild: rebuild).fetch(name.to_sym) do - klass = name.classify.safe_constantize - if klass.nil? - warn "[POLYMORPHIC TYPE NOT FOUND] No polymorphic types found for #{name}" - else - polymorphic_type = format_polymorphic_klass_type(klass) - warn "[POLYMORPHIC TYPE] Found polymorphic types through reflection for #{name}: #{polymorphic_type}" - polymorphic_types_lookup[name.to_sym] = [polymorphic_type] - end + polymorphic_types_lookup(rebuild: rebuild).fetch(name.to_sym, &handle_polymorphic_type_name_found) + end + + def handle_polymorphic_type_name_found + @handle_polymorphic_type_name_found ||= lambda do |name| + warn "[POLYMORPHIC TYPE NOT FOUND] No polymorphic types found for #{name}" + nil end end @@ -51,31 +49,34 @@ def build_polymorphic_types_lookup_from_object_space {}.tap do |lookup| ObjectSpace.each_object do |klass| next unless Module === klass - is_active_record_inspectable = ActiveRecord::Base > klass - is_active_record_inspectable &&= klass.respond_to?(:reflect_on_all_associations, true) - is_active_record_inspectable &&= format_polymorphic_klass_type(klass).present? - if is_active_record_inspectable - add_polymorphic_types_lookup(klass: klass, lookup: lookup) - end + next unless ActiveRecord::Base > klass + add_polymorphic_types_lookup(klass: klass, lookup: lookup) end end end + # TODO(BF): Consider adding the following conditions + # is_active_record_inspectable = true + # is_active_record_inspectable &&= klass.respond_to?(:reflect_on_all_associations, true) + # is_active_record_inspectable &&= format_polymorphic_klass_type(klass).present? + # return unless is_active_record_inspectable def add_polymorphic_types_lookup(klass:, lookup:) klass.reflect_on_all_associations(:has_many).select { |r| r.options[:as] }.each do |reflection| (lookup[reflection.options[:as]] ||= []) << format_polymorphic_klass_type(klass).underscore end end + # TODO(BF): Consider adding the following conditions + # klass.name || + # begin + # klass.model_name.name + # rescue ArgumentError => ex + # # klass.base_class may be nil + # warn "[POLYMORPHIC TYPE] #{__callee__} #{klass} #{ex.inspect}" + # nil + # end def format_polymorphic_klass_type(klass) - klass.name || - begin - klass.model_name.name - rescue ArgumentError => ex - # klass.base_class may be nil - warn "[POLYMORPHIC TYPE] #{__callee__} #{klass} #{ex.inspect}" - nil - end + klass.name end end end diff --git a/test/unit/utils/polymorphic_types_lookup_test.rb b/test/unit/utils/polymorphic_types_lookup_test.rb new file mode 100644 index 00000000..838ed878 --- /dev/null +++ b/test/unit/utils/polymorphic_types_lookup_test.rb @@ -0,0 +1,35 @@ +require File.expand_path('../../../test_helper', __FILE__) + +class PolymorphicTypesLookupTest < ActiveSupport::TestCase + def setup + JSONAPI::Utils::PolymorphicTypesLookup.polymorphic_types_lookup_clear! + end + + def test_build_polymorphic_types_lookup_from_object_space + expected = { + :imageable=>["product", "document"] + } + actual = JSONAPI::Utils::PolymorphicTypesLookup.build_polymorphic_types_lookup_from_object_space + actual_keys = actual.keys.sort + assert_equal(actual_keys, expected.keys.sort) + actual_keys.each do |actual_key| + actual_values = actual[actual_key].sort + expected_values = expected[actual_key].sort + assert_equal(actual_values, expected_values) + end + end + + def test_build_polymorphic_types_lookup_from_descendants + expected = { + :imageable=>["document", "product"] + } + actual = JSONAPI::Utils::PolymorphicTypesLookup.build_polymorphic_types_lookup_from_descendants + actual_keys = actual.keys.sort + assert_equal(actual_keys, expected.keys.sort) + actual_keys.each do |actual_key| + actual_values = actual[actual_key].sort + expected_values = expected[actual_key].sort + assert_equal(actual_values, expected_values) + end + end +end From ed41c8cf428ff5dbd7bcfc1becc5aa56ba4d71bf Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 24 Jan 2024 09:12:14 -0600 Subject: [PATCH 7/8] feat: make polymorphic type lookup configurable --- lib/jsonapi/utils/polymorphic_types_lookup.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/jsonapi/utils/polymorphic_types_lookup.rb b/lib/jsonapi/utils/polymorphic_types_lookup.rb index 219349d8..7457410a 100644 --- a/lib/jsonapi/utils/polymorphic_types_lookup.rb +++ b/lib/jsonapi/utils/polymorphic_types_lookup.rb @@ -5,6 +5,10 @@ module Utils module PolymorphicTypesLookup extend self + singleton_class.attr_accessor :build_polymorphic_types_lookup_strategy + self.build_polymorphic_types_lookup_strategy = + :build_polymorphic_types_lookup_from_object_space + def polymorphic_types(name, rebuild: false) polymorphic_types_lookup(rebuild: rebuild).fetch(name.to_sym, &handle_polymorphic_type_name_found) end @@ -29,10 +33,6 @@ def build_polymorphic_types_lookup public_send(build_polymorphic_types_lookup_strategy) end - def build_polymorphic_types_lookup_strategy - :build_polymorphic_types_lookup_from_object_space - end - def build_polymorphic_types_lookup_from_descendants {}.tap do |lookup| ActiveRecord::Base From 93ac3142fdd44ca5c98c4a83dcf4c6ec54f8a26b Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 24 Jan 2024 09:16:31 -0600 Subject: [PATCH 8/8] feat: clear polymorphic lookup after initialize --- lib/jsonapi/resources/railtie.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/jsonapi/resources/railtie.rb b/lib/jsonapi/resources/railtie.rb index 10fb3c05..02050879 100644 --- a/lib/jsonapi/resources/railtie.rb +++ b/lib/jsonapi/resources/railtie.rb @@ -18,6 +18,10 @@ class Railtie < ::Rails::Railtie ::JSONAPI::MimeTypes.parser.call(body) } end + + initializer "jsonapi_resources.initialize", after: :initialize do + JSONAPI::Utils::PolymorphicTypesLookup.polymorphic_types_lookup_clear! + end end end end