Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run the polymorphic bug #1349

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions lib/jsonapi/relationship.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,48 @@ def table_name
end

def self.polymorphic_types(name)
polymorphic_types_lookup[name.to_sym]
end

def self.polymorphic_types_lookup(warn_on_no_name: false)
@poly_hash ||= {}.tap do |hash|
ObjectSpace.each_object do |klass|
next unless Module === klass
if ActiveRecord::Base > klass
klass.reflect_on_all_associations(:has_many).select{|r| r.options[:as] }.each do |reflection|
(hash[reflection.options[:as]] ||= []) << klass.name.downcase
end
build_active_record_polymorphic_types_lookup(hash, warn_on_no_name: warn_on_no_name)
end
end

def self.build_active_record_polymorphic_types_lookup(hash, warn_on_no_name: false)
candidate_active_record_polymorphic_classes.each do |klass|
if klass.name.nil?
if warn_on_no_name
model_name =
if klass.respond_to?(:model_name)
begin
klass.model_name.name
rescue ArgumentError => e
"Responds to ActiveModel::Naming but #{e.message}"
end
else
"Does not extend ActiveModel::Naming"
end
warn "No class name found for #{klass} (#{model_name})"
end
next
end
klass.reflect_on_all_associations(:has_many).select{|r| r.options[:as] }.each do |reflection|
(hash[reflection.options[:as]] ||= []) << klass.name.downcase
end
end
end

def self.candidate_active_record_polymorphic_classes
candidate_polymorphic_classes = []
ObjectSpace.each_object do |klass|
next unless Module === klass
if ActiveRecord::Base > klass
candidate_polymorphic_classes << klass
end
end
@poly_hash[name.to_sym]
candidate_polymorphic_classes
end

def resource_types
Expand Down
50 changes: 50 additions & 0 deletions test/bug_1305_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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)
pp json_response
end
assert_equal status, last_response.status, failure_reason
end

def app
Rails.application
end
end
59 changes: 59 additions & 0 deletions test/fixtures/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,19 @@
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
Expand Down Expand Up @@ -643,6 +656,22 @@ 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
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

Expand Down Expand Up @@ -1246,6 +1275,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
Expand Down Expand Up @@ -2688,6 +2729,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'))
Expand Down
14 changes: 14 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
ActiveSupport::Deprecation.silenced = true

puts "Testing With RAILS VERSION #{Rails.version}"
Minitest.after_run do
puts "Found JSONAPI::Relationship.polymorphic_types_lookup"
puts "\t #{JSONAPI::Relationship.polymorphic_types_lookup(warn_on_no_name: true).inspect}\n"
end

class TestApp < Rails::Application
config.eager_load = false
Expand Down Expand Up @@ -450,6 +454,16 @@ class CatResource < JSONAPI::Resource

mount MyEngine::Engine => "/boomshaka", as: :my_engine
mount ApiV2Engine::Engine => "/api_v2", as: :api_v2_engine

jsonapi_resources :contact_media do
jsonapi_relationships
end
jsonapi_resources :individuals do
jsonapi_relationships
end
jsonapi_resources :organizations do
jsonapi_relationships
end
end

MyEngine::Engine.routes.draw do
Expand Down