Skip to content

Commit 311b1fe

Browse files
bf4lgebhardt
andauthored
fix: format model polymorphic type from resource object type (#1435)
* test: failing request posting sti with polymorphic has one * fix: polymorphic resource assignment * Add polymorphic_type_for method * Favor classify over singularize.camelize --------- Co-authored-by: lgebhardt <larry@cerebris.com>
1 parent 51c9592 commit 311b1fe

File tree

6 files changed

+62
-10
lines changed

6 files changed

+62
-10
lines changed

lib/jsonapi/acts_as_resource_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def base_url
164164
end
165165

166166
def resource_klass_name
167-
@resource_klass_name ||= "#{self.class.name.underscore.sub(/_controller$/, '').singularize}_resource".camelize
167+
@resource_klass_name ||= "#{self.class.name.underscore.sub(/_controller$/, '').classify}Resource"
168168
end
169169

170170
def verify_content_type_header

lib/jsonapi/link_builder.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def build_engine
9292

9393
begin
9494
unless scopes.empty?
95-
"#{ scopes.first.to_s.camelize }::Engine".safe_constantize
95+
"#{ scopes.first.to_s.classify }::Engine".safe_constantize
9696
end
9797

9898
# :nocov:

lib/jsonapi/relationship.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class ToOne < Relationship
155155

156156
def initialize(name, options = {})
157157
super
158-
@class_name = options.fetch(:class_name, name.to_s.camelize)
158+
@class_name = options.fetch(:class_name, name.to_s.classify)
159159
@foreign_key ||= "#{name}_id".to_sym
160160
@foreign_key_on = options.fetch(:foreign_key_on, :self)
161161
# if parent_resource
@@ -231,7 +231,7 @@ class ToMany < Relationship
231231

232232
def initialize(name, options = {})
233233
super
234-
@class_name = options.fetch(:class_name, name.to_s.camelize.singularize)
234+
@class_name = options.fetch(:class_name, name.to_s.classify)
235235
@foreign_key ||= "#{name.to_s.singularize}_ids".to_sym
236236
@reflect = options.fetch(:reflect, true) == true
237237
# if parent_resource

lib/jsonapi/resource_common.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ def resource_klass_for_model(model)
561561
end
562562

563563
def _resource_name_from_type(type)
564-
"#{type.to_s.underscore.singularize}_resource".camelize
564+
"#{type.to_s.classify}Resource"
565565
end
566566

567567
def resource_type_for(model)
@@ -578,6 +578,10 @@ def resource_type_for(model)
578578
end
579579
end
580580

581+
def polymorphic_type_for(model_name)
582+
model_name&.to_s&.classify
583+
end
584+
581585
attr_accessor :_attributes,
582586
:_relationships,
583587
:_type,
@@ -1200,12 +1204,12 @@ def define_relationship_methods(relationship_name, relationship_klass, options)
12001204
def define_foreign_key_setter(relationship)
12011205
if relationship.polymorphic?
12021206
define_on_resource "#{relationship.foreign_key}=" do |v|
1203-
_model.method("#{relationship.foreign_key}=").call(v[:id])
1204-
_model.public_send("#{relationship.polymorphic_type}=", v[:type])
1207+
_model.public_send("#{relationship.foreign_key}=", v[:id])
1208+
_model.public_send("#{relationship.polymorphic_type}=", self.class.polymorphic_type_for(v[:type]))
12051209
end
12061210
else
12071211
define_on_resource "#{relationship.foreign_key}=" do |value|
1208-
_model.method("#{relationship.foreign_key}=").call(value)
1212+
_model.public_send("#{relationship.foreign_key}=", value)
12091213
end
12101214
end
12111215
relationship.foreign_key

test/fixtures/active_record.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
t.string :drive_layout
276276
t.string :serial_number
277277
t.integer :person_id
278+
t.references :imageable, polymorphic: true, index: true
278279
t.timestamps null: false
279280
end
280281

@@ -734,6 +735,9 @@ class Picture < ActiveRecord::Base
734735

735736
class Vehicle < ActiveRecord::Base
736737
belongs_to :person
738+
belongs_to :imageable, polymorphic: true
739+
# belongs_to :document, -> { where( pictures: { imageable_type: 'Document' } ) }, foreign_key: 'imageable_id'
740+
# belongs_to :product, -> { where( pictures: { imageable_type: 'Product' } ) }, foreign_key: 'imageable_id'
737741
end
738742

739743
class Car < Vehicle
@@ -743,13 +747,13 @@ class Boat < Vehicle
743747
end
744748

745749
class Document < ActiveRecord::Base
746-
has_many :pictures, as: :imageable
750+
has_many :pictures, as: :imageable # polymorphic
747751
belongs_to :author, class_name: 'Person', foreign_key: 'author_id'
748752
has_one :file_properties, as: :fileable
749753
end
750754

751755
class Product < ActiveRecord::Base
752-
has_many :pictures, as: :imageable
756+
has_many :pictures, as: :imageable # polymorphic
753757
belongs_to :designer, class_name: 'Person', foreign_key: 'designer_id'
754758
has_one :file_properties, as: :fileable
755759
end
@@ -1336,6 +1340,7 @@ class VehicleResource < JSONAPI::Resource
13361340
immutable
13371341

13381342
has_one :person
1343+
has_one :imageable, polymorphic: true
13391344
attributes :make, :model, :serial_number
13401345
end
13411346

@@ -1915,6 +1920,8 @@ class PreferencesResource < PreferencesResource; end
19151920
class SectionResource < SectionResource; end
19161921
class TagResource < TagResource; end
19171922
class CommentResource < CommentResource; end
1923+
class DocumentResource < DocumentResource; end
1924+
class ProductResource < ProductResource; end
19181925
class VehicleResource < VehicleResource; end
19191926
class CarResource < CarResource; end
19201927
class BoatResource < BoatResource; end

test/integration/requests/request_test.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,47 @@ def test_post_polymorphic_with_has_many_relationship
359359
assert_equal Car, person.vehicles.fourth.class
360360
end
361361

362+
def test_post_sti_polymorphic_with_has_one_relationship
363+
post '/cars', params:
364+
{
365+
'data' => {
366+
'type' => 'cars',
367+
'attributes' => {
368+
'make' => 'Mazda',
369+
'model' => 'Miata MX5',
370+
'drive_layout' => 'Front Engine RWD',
371+
'serial_number' => '32432adfsfdysua',
372+
},
373+
'relationships' => {
374+
'person' => {
375+
'data' => {
376+
'type' => 'people', 'id' => '1001',
377+
}
378+
},
379+
'imageable' => {
380+
'data' => {
381+
'type' => 'products', 'id' => '1',
382+
}
383+
},
384+
}
385+
}
386+
}.to_json,
387+
headers: {
388+
'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE,
389+
'Accept' => JSONAPI::MEDIA_TYPE
390+
}
391+
392+
assert_jsonapi_response 201
393+
394+
body = response.parsed_body
395+
car = Vehicle.find(body.dig("data", "id"))
396+
397+
assert_equal "Car", car.type
398+
assert_equal "Mazda", car.make
399+
assert_equal Product, car.imageable.class
400+
assert_equal Person, car.person.class
401+
end
402+
362403
def test_post_polymorphic_invalid_with_wrong_type
363404
post '/people', params:
364405
{

0 commit comments

Comments
 (0)