@@ -159,7 +159,7 @@ def _create_has_many_links(association_type, association_key_values)
159159 association = self . class . _associations [ association_type ]
160160
161161 association_key_values . each do |association_key_value |
162- related_resource = Resource . resource_for ( self . class . module_path + association . type . to_s ) . find_by_key ( association_key_value , context : @context )
162+ related_resource = association . resource_klass . find_by_key ( association_key_value , context : @context )
163163
164164 # ToDo: Add option to skip relations that already exist instead of returning an error?
165165 relation = @model . send ( association . type ) . where ( association . primary_key => association_key_value ) . first
@@ -364,8 +364,33 @@ def fields
364364 _associations . keys | _attributes . keys
365365 end
366366
367- def apply_includes ( records , directives )
368- records = records . includes ( *directives . model_includes ) if directives
367+ def resolve_association_names_to_relations ( resource_klass , model_includes , options = { } )
368+ case model_includes
369+ when Array
370+ return model_includes . map do |value |
371+ resolve_association_names_to_relations ( resource_klass , value , options )
372+ end
373+ when Hash
374+ model_includes . keys . each do |key |
375+ association = resource_klass . _associations [ key ]
376+ value = model_includes [ key ]
377+ model_includes . delete ( key )
378+ model_includes [ association . relation_name ( options ) ] = resolve_association_names_to_relations ( association . resource_klass , value , options )
379+ end
380+ return model_includes
381+ when Symbol
382+ association = resource_klass . _associations [ model_includes ]
383+ return association . relation_name ( options )
384+ end
385+ end
386+
387+ def apply_includes ( records , options = { } )
388+ include_directives = options [ :include_directives ]
389+ if include_directives
390+ model_includes = resolve_association_names_to_relations ( self , include_directives . model_includes , options )
391+ records = records . includes ( model_includes )
392+ end
393+
369394 records
370395 end
371396
@@ -395,7 +420,7 @@ def apply_filters(records, filters, options = {})
395420 filters . each do |filter , value |
396421 if _associations . include? ( filter )
397422 if _associations [ filter ] . is_a? ( JSONAPI ::Association ::HasMany )
398- required_includes . push ( filter )
423+ required_includes . push ( filter . to_s )
399424 records = apply_filter ( records , "#{ filter } .#{ _associations [ filter ] . primary_key } " , value , options )
400425 else
401426 records = apply_filter ( records , "#{ _associations [ filter ] . foreign_key } " , value , options )
@@ -407,20 +432,16 @@ def apply_filters(records, filters, options = {})
407432 end
408433
409434 if required_includes . any?
410- records . includes ( required_includes )
411- elsif records . respond_to? :to_ary
412- records
413- else
414- records . all
435+ records = apply_includes ( records , options . merge ( include_directives : IncludeDirectives . new ( required_includes ) ) )
415436 end
437+
438+ records
416439 end
417440
418441 def filter_records ( filters , options )
419- include_directives = options [ :include_directives ]
420-
421442 records = records ( options )
422- records = apply_includes ( records , include_directives )
423- apply_filters ( records , filters , options )
443+ records = apply_filters ( records , filters , options )
444+ apply_includes ( records , options )
424445 end
425446
426447 def sort_records ( records , order_options )
@@ -453,9 +474,8 @@ def find(filters, options = {})
453474
454475 def find_by_key ( key , options = { } )
455476 context = options [ :context ]
456- include_directives = options [ :include_directives ]
457477 records = records ( options )
458- records = apply_includes ( records , include_directives )
478+ records = apply_includes ( records , options )
459479 model = records . where ( { _primary_key => key } ) . first
460480 if model . nil?
461481 raise JSONAPI ::Exceptions ::RecordNotFound . new ( key )
@@ -555,7 +575,7 @@ def _allowed_filters
555575 def _resource_name_from_type ( type )
556576 class_name = @@resource_types [ type ]
557577 if class_name . nil?
558- class_name = "#{ type . to_s . singularize } _resource" . camelize
578+ class_name = "#{ type . to_s . underscore . singularize } _resource" . camelize
559579 @@resource_types [ type ] = class_name
560580 end
561581 return class_name
@@ -619,62 +639,70 @@ def _associate(klass, *attrs)
619639 attrs . each do |attr |
620640 check_reserved_association_name ( attr )
621641
622- @_associations [ attr ] = klass . new ( attr , options )
642+ association = @_associations [ attr ] = klass . new ( attr , options )
623643
624- foreign_key = @_associations [ attr ] . foreign_key
644+ associated_records_method_name = case association
645+ when JSONAPI ::Association ::HasOne then "record_for_#{ attr } "
646+ when JSONAPI ::Association ::HasMany then "records_for_#{ attr } "
647+ end
625648
626- define_method foreign_key do
627- @model . method ( foreign_key ) . call
628- end unless method_defined? ( foreign_key )
649+ foreign_key = association . foreign_key
629650
630651 define_method "#{ foreign_key } =" do |value |
631652 @model . method ( "#{ foreign_key } =" ) . call ( value )
632653 end unless method_defined? ( "#{ foreign_key } =" )
633654
634- associated_records_method_name = case @_associations [ attr ]
635- when JSONAPI ::Association ::HasOne then "record_for_#{ attr } "
636- when JSONAPI ::Association ::HasMany then "records_for_#{ attr } "
637- end
638-
639655 define_method associated_records_method_name do |options = { } |
640- records_for ( attr , options )
656+ relation_name = association . relation_name ( options . merge ( { context : @context } ) )
657+ records_for ( relation_name , options )
641658 end unless method_defined? ( associated_records_method_name )
642659
643- if @_associations [ attr ] . is_a? ( JSONAPI ::Association ::HasOne )
644- define_method attr do
645- type_name = self . class . _associations [ attr ] . type . to_s
646- resource_class = Resource . resource_for ( self . class . module_path + type_name )
647- if resource_class
660+ if association . is_a? ( JSONAPI ::Association ::HasOne )
661+ define_method foreign_key do
662+ @model . method ( foreign_key ) . call
663+ end unless method_defined? ( foreign_key )
664+
665+ define_method attr do |options = { } |
666+ resource_klass = association . resource_klass
667+ if resource_klass
648668 associated_model = public_send ( associated_records_method_name )
649- return associated_model ? resource_class . new ( associated_model , @context ) : nil
669+ return associated_model ? resource_klass . new ( associated_model , @context ) : nil
650670 end
651671 end unless method_defined? ( attr )
652- elsif @_associations [ attr ] . is_a? ( JSONAPI ::Association ::HasMany )
672+ elsif association . is_a? ( JSONAPI ::Association ::HasMany )
673+ define_method foreign_key do
674+ records = public_send ( associated_records_method_name )
675+ return records . collect do |record |
676+ record . send ( association . resource_klass . _primary_key )
677+ end
678+ end unless method_defined? ( foreign_key )
653679 define_method attr do |options = { } |
654- type_name = self . class . _associations [ attr ] . type . to_s
655- resource_class = Resource . resource_for ( self . class . module_path + type_name )
680+ resource_klass = association . resource_klass
681+ records = public_send ( associated_records_method_name )
682+
656683 filters = options . fetch ( :filters , { } )
684+ unless filters . nil? || filters . empty?
685+ records = resource_klass . apply_filters ( records , filters , options )
686+ end
687+
657688 sort_criteria = options . fetch ( :sort_criteria , { } )
658- paginator = options [ :paginator ]
689+ unless sort_criteria . nil? || sort_criteria . empty?
690+ order_options = self . class . construct_order_options ( sort_criteria )
691+ records = resource_klass . apply_sort ( records , order_options )
692+ end
659693
660- resources = [ ]
694+ paginator = options [ :paginator ]
695+ if paginator
696+ records = resource_klass . apply_pagination ( records , paginator , order_options )
697+ end
661698
662- if resource_class
663- records = public_send ( associated_records_method_name )
664- records = resource_class . apply_filters ( records , filters , options )
665- order_options = self . class . construct_order_options ( sort_criteria )
666- records = resource_class . apply_sort ( records , order_options )
667- records = resource_class . apply_pagination ( records , paginator , order_options )
668- records . each do |record |
669- resources . push resource_class . new ( record , @context )
670- end
699+ return records . collect do |record |
700+ resource_klass . new ( record , @context )
671701 end
672- return resources
673702 end unless method_defined? ( attr )
674703 end
675704 end
676705 end
677706 end
678-
679707 end
680708end
0 commit comments