Skip to content

Commit 280ccea

Browse files
committed
Rework model_name in derived resources
Fixes an issue where the recreated relationships might be using the wrong model_name if the model_name is changed in a resource that is derived from a non abstract resource, such as done in many of the tests. Breaking change: Derived resources now use the model name of their base resource, if it is not abstract. Cleans up the tests to not have the warnings about missing models. Fixes issue in _model_class related to #952, and renames @model (class level) to @model_class to avoid confusion with instance level @model Fixes #952, #654
1 parent c1ff996 commit 280ccea

4 files changed

Lines changed: 67 additions & 43 deletions

File tree

lib/jsonapi/resource.rb

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -410,18 +410,15 @@ def inherited(subclass)
410410
subclass.immutable(false)
411411
subclass.caching(false)
412412
subclass._attributes = (_attributes || {}).dup
413+
413414
subclass._model_hints = (_model_hints || {}).dup
414415

415-
subclass._relationships = {}
416-
# Add the relationships from the base class to the subclass using the original options
417-
if _relationships.is_a?(Hash)
418-
_relationships.each_value do |relationship|
419-
options = relationship.options.dup
420-
options[:parent_resource] = subclass
421-
subclass._add_relationship(relationship.class, relationship.name, options)
422-
end
416+
unless _model_name.empty?
417+
subclass.model_name(_model_name, add_model_hint: (_model_hints && !_model_hints[_model_name].nil?) == true)
423418
end
424419

420+
subclass.rebuild_relationships(_relationships || {})
421+
425422
subclass._allowed_filters = (_allowed_filters || Set.new).dup
426423

427424
type = subclass.name.demodulize.sub(/Resource$/, '').underscore
@@ -432,6 +429,20 @@ def inherited(subclass)
432429
check_reserved_resource_name(subclass._type, subclass.name)
433430
end
434431

432+
def rebuild_relationships(relationships)
433+
original_relationships = relationships.deep_dup
434+
435+
@_relationships = {}
436+
437+
if original_relationships.is_a?(Hash)
438+
original_relationships.each_value do |relationship|
439+
options = relationship.options.dup
440+
options[:parent_resource] = self
441+
_add_relationship(relationship.class, relationship.name, options)
442+
end
443+
end
444+
end
445+
435446
def resource_for(type)
436447
type = type.underscore
437448
type_with_module = type.include?('/') ? type : module_path + type
@@ -554,6 +565,8 @@ def model_name(model, options = {})
554565
@_model_name = model.to_sym
555566

556567
model_hint(model: @_model_name, resource: self) unless options[:add_model_hint] == false
568+
569+
rebuild_relationships(_relationships)
557570
end
558571

559572
def model_hint(model: _model_name, resource: _type)
@@ -908,10 +921,11 @@ def _model_name
908921
if _abstract
909922
return ''
910923
else
911-
return @_model_name if defined?(@_model_name)
924+
return @_model_name.to_s if defined?(@_model_name)
912925
class_name = self.name
913926
return '' if class_name.nil?
914-
return @_model_name = class_name.demodulize.sub(/Resource$/, '')
927+
@_model_name = class_name.demodulize.sub(/Resource$/, '')
928+
return @_model_name.to_s
915929
end
916930
end
917931

@@ -982,11 +996,17 @@ def attribute_caching_context(context)
982996
def _model_class
983997
return nil if _abstract
984998

985-
return @model if defined?(@model)
986-
return nil if self.name.to_s.blank? && _model_name.to_s.blank?
987-
@model = _model_name.to_s.safe_constantize
988-
warn "[MODEL NOT FOUND] Model could not be found for #{self.name}. If this a base Resource declare it as abstract." if @model.nil?
989-
@model
999+
return @model_class if @model_class
1000+
1001+
model_name = _model_name
1002+
return nil if model_name.to_s.blank?
1003+
1004+
@model_class = model_name.to_s.safe_constantize
1005+
if @model_class.nil?
1006+
warn "[MODEL NOT FOUND] Model could not be found for #{self.name}. If this a base Resource declare it as abstract."
1007+
end
1008+
1009+
@model_class
9901010
end
9911011

9921012
def _allowed_filter?(filter)

test/fixtures/active_record.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,7 @@ class CompanyResource < JSONAPI::Resource
10051005
end
10061006

10071007
class FirmResource < CompanyResource
1008+
model_name "Firm"
10081009
end
10091010

10101011
class TagResource < JSONAPI::Resource

test/unit/jsonapi_request/jsonapi_request_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class CatResource < JSONAPI::Resource
44
attribute :name
55
attribute :breed
66

7-
belongs_to :mother, class_name: 'Cat'
7+
has_one :mother, class_name: 'Cat'
88
has_one :father, class_name: 'Cat'
99

1010
filters :name

test/unit/resource/resource_test.rb

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ class NoMatchAbstractResource < JSONAPI::Resource
4747
abstract
4848
end
4949

50-
class CatResource < JSONAPI::Resource
50+
class FelineResource < JSONAPI::Resource
51+
model_name 'Cat'
52+
5153
attribute :name
5254
attribute :breed
5355
attribute :kind, :delegate => :breed
@@ -99,6 +101,7 @@ class RelatedResource < MyModule::RelatedResource
99101
end
100102

101103
class PostWithReadonlyAttributesResource < JSONAPI::Resource
104+
model_name 'Post'
102105
attribute :title, readonly: true
103106
has_one :author, readonly: true
104107
end
@@ -180,7 +183,7 @@ def test_derived_not_abstract
180183
def test_nil_model_class
181184
# ToDo:Figure out why this test does not work on Rails 4.0
182185
# :nocov:
183-
if Rails::VERSION::MAJOR >= 4 && Rails::VERSION::MINOR >= 1
186+
if (Rails::VERSION::MAJOR >= 4 && Rails::VERSION::MINOR >= 1) || (Rails::VERSION::MAJOR >= 5)
184187
assert_output nil, "[MODEL NOT FOUND] Model could not be found for NoMatchResource. If this a base Resource declare it as abstract.\n" do
185188
assert_nil NoMatchResource._model_class
186189
end
@@ -199,13 +202,13 @@ def test_model_alternate
199202
end
200203

201204
def test_class_attributes
202-
attrs = CatResource._attributes
205+
attrs = FelineResource._attributes
203206
assert_kind_of(Hash, attrs)
204207
assert_equal(attrs.keys.size, 4)
205208
end
206209

207210
def test_class_relationships
208-
relationships = CatResource._relationships
211+
relationships = FelineResource._relationships
209212
assert_kind_of(Hash, relationships)
210213
assert_equal(relationships.size, 2)
211214
end
@@ -219,16 +222,16 @@ def test_replace_polymorphic_to_one_link
219222
end
220223

221224
def test_duplicate_relationship_name
222-
assert_output nil, "[DUPLICATE RELATIONSHIP] `mother` has already been defined in CatResource.\n" do
223-
CatResource.instance_eval do
225+
assert_output nil, "[DUPLICATE RELATIONSHIP] `mother` has already been defined in FelineResource.\n" do
226+
FelineResource.instance_eval do
224227
has_one :mother, class_name: 'Cat'
225228
end
226229
end
227230
end
228231

229232
def test_duplicate_attribute_name
230-
assert_output nil, "[DUPLICATE ATTRIBUTE] `name` has already been defined in CatResource.\n" do
231-
CatResource.instance_eval do
233+
assert_output nil, "[DUPLICATE ATTRIBUTE] `name` has already been defined in FelineResource.\n" do
234+
FelineResource.instance_eval do
232235
attribute :name
233236
end
234237
end
@@ -299,7 +302,7 @@ def test_find_by_key_with_customized_base_records
299302
end
300303

301304
def test_updatable_fields_does_not_include_id
302-
assert(!CatResource.updatable_fields.include?(:id))
305+
assert(!FelineResource.updatable_fields.include?(:id))
303306
end
304307

305308
def test_filter_on_to_many_relationship_id
@@ -443,60 +446,60 @@ def apply_pagination(records, criteria, order_options)
443446
end
444447

445448
def test_key_type_integer
446-
CatResource.instance_eval do
449+
FelineResource.instance_eval do
447450
key_type :integer
448451
end
449452

450-
assert CatResource.verify_key('45')
451-
assert CatResource.verify_key(45)
453+
assert FelineResource.verify_key('45')
454+
assert FelineResource.verify_key(45)
452455

453456
assert_raises JSONAPI::Exceptions::InvalidFieldValue do
454-
CatResource.verify_key('45,345')
457+
FelineResource.verify_key('45,345')
455458
end
456459

457460
ensure
458-
CatResource.instance_eval do
461+
FelineResource.instance_eval do
459462
key_type nil
460463
end
461464
end
462465

463466
def test_key_type_string
464-
CatResource.instance_eval do
467+
FelineResource.instance_eval do
465468
key_type :string
466469
end
467470

468-
assert CatResource.verify_key('45')
469-
assert CatResource.verify_key(45)
471+
assert FelineResource.verify_key('45')
472+
assert FelineResource.verify_key(45)
470473

471474
assert_raises JSONAPI::Exceptions::InvalidFieldValue do
472-
CatResource.verify_key('45,345')
475+
FelineResource.verify_key('45,345')
473476
end
474477

475478
ensure
476-
CatResource.instance_eval do
479+
FelineResource.instance_eval do
477480
key_type nil
478481
end
479482
end
480483

481484
def test_key_type_uuid
482-
CatResource.instance_eval do
485+
FelineResource.instance_eval do
483486
key_type :uuid
484487
end
485488

486-
assert CatResource.verify_key('f1a4d5f2-e77a-4d0a-acbb-ee0b98b3f6b5')
489+
assert FelineResource.verify_key('f1a4d5f2-e77a-4d0a-acbb-ee0b98b3f6b5')
487490

488491
assert_raises JSONAPI::Exceptions::InvalidFieldValue do
489-
CatResource.verify_key('f1a-e77a-4d0a-acbb-ee0b98b3f6b5')
492+
FelineResource.verify_key('f1a-e77a-4d0a-acbb-ee0b98b3f6b5')
490493
end
491494

492495
ensure
493-
CatResource.instance_eval do
496+
FelineResource.instance_eval do
494497
key_type nil
495498
end
496499
end
497500

498501
def test_key_type_proc
499-
CatResource.instance_eval do
502+
FelineResource.instance_eval do
500503
key_type -> (key, context) {
501504
return key if key.nil?
502505
if key.to_s.match(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/)
@@ -507,14 +510,14 @@ def test_key_type_proc
507510
}
508511
end
509512

510-
assert CatResource.verify_key('f1a4d5f2-e77a-4d0a-acbb-ee0b98b3f6b5')
513+
assert FelineResource.verify_key('f1a4d5f2-e77a-4d0a-acbb-ee0b98b3f6b5')
511514

512515
assert_raises JSONAPI::Exceptions::InvalidFieldValue do
513-
CatResource.verify_key('f1a-e77a-4d0a-acbb-ee0b98b3f6b5')
516+
FelineResource.verify_key('f1a-e77a-4d0a-acbb-ee0b98b3f6b5')
514517
end
515518

516519
ensure
517-
CatResource.instance_eval do
520+
FelineResource.instance_eval do
518521
key_type nil
519522
end
520523
end

0 commit comments

Comments
 (0)