diff --git a/lib/jsonapi/active_relation_retrieval.rb b/lib/jsonapi/active_relation_retrieval.rb index fc5aaa2a..da7577cc 100644 --- a/lib/jsonapi/active_relation_retrieval.rb +++ b/lib/jsonapi/active_relation_retrieval.rb @@ -9,6 +9,10 @@ def find_related_ids(relationship, options) end module ClassMethods + def allowed_related_through + @allowed_related_through ||= [:inverse, :primary] + end + def default_find_related_through(polymorphic = false) if polymorphic JSONAPI.configuration.default_find_related_through_polymorphic @@ -127,6 +131,11 @@ def find_fragments(filters, options) options: options) if options[:cache] + # When using caching the a two step process is used. First the records ids are retrieved and then the + # records are retrieved using the ids. Then the ids are used to query the database again to get the + # cache misses. In the second phase the records are not sorted or paginated and the `records_for_populate` + # method is used to ensure any dependent includes or custom database fields are calculated. + # This alias is going to be resolve down to the model's table name and will not actually be an alias resource_table_alias = resource_klass._table_name @@ -197,6 +206,10 @@ def find_fragments(filters, options) warn "Performance issue detected: `#{self.name.to_s}.records` returned non-normalized results in `#{self.name.to_s}.find_fragments`." end else + # When not using caching resources can be generated after querying. The `records_for_populate` + # method is merged in to ensure any dependent includes or custom database fields are calculated. + records = records.merge(records_for_populate(options)) + linkage_fields = [] linkage_relationships.each do |linkage_relationship| @@ -320,10 +333,16 @@ def _find_related_monomorphic_fragments_through_primary(source_fragments, relati resource_klass = relationship.resource_klass linkage_relationships = resource_klass.to_one_relationships_for_linkage(include_directives[:include_related]) - sort_criteria = [] - options[:sort_criteria].try(:each) do |sort| - field = sort[:field].to_s == 'id' ? resource_klass._primary_key : sort[:field] - sort_criteria << { field: field, direction: sort[:direction] } + # Do not sort the related_fragments. This can be keyed off `connect_source_identity` to indicate whether this + # is a related resource primary step vs. an include step. + sort_related_fragments = !connect_source_identity + + if sort_related_fragments + sort_criteria = [] + options[:sort_criteria].try(:each) do |sort| + field = sort[:field].to_s == 'id' ? resource_klass._primary_key : sort[:field] + sort_criteria << { field: field, direction: sort[:direction] } + end end join_manager = ActiveRelation::JoinManagerThroughPrimary.new(resource_klass: self, diff --git a/lib/jsonapi/active_relation_retrieval_v09.rb b/lib/jsonapi/active_relation_retrieval_v09.rb index bc538743..00fb24d5 100644 --- a/lib/jsonapi/active_relation_retrieval_v09.rb +++ b/lib/jsonapi/active_relation_retrieval_v09.rb @@ -15,8 +15,12 @@ def records_for(relation_name) end module ClassMethods + def allowed_related_through + @allowed_related_through ||= [:model_includes] + end + def default_find_related_through(polymorphic = false) - polymorphic ? :model : :model + polymorphic ? :model_includes : :model_includes end # Finds Resources using the `filters`. Pagination and sort options are used when provided diff --git a/lib/jsonapi/active_relation_retrieval_v10.rb b/lib/jsonapi/active_relation_retrieval_v10.rb index fd5fbad2..aeb7abb6 100644 --- a/lib/jsonapi/active_relation_retrieval_v10.rb +++ b/lib/jsonapi/active_relation_retrieval_v10.rb @@ -9,6 +9,10 @@ def find_related_ids(relationship, options) end module ClassMethods + def allowed_related_through + @allowed_related_through ||= [:primary] + end + def default_find_related_through(polymorphic = false) polymorphic ? :primary : :primary end diff --git a/lib/jsonapi/configuration.rb b/lib/jsonapi/configuration.rb index 552674f9..1c66948d 100644 --- a/lib/jsonapi/configuration.rb +++ b/lib/jsonapi/configuration.rb @@ -178,9 +178,12 @@ def initialize # Available strategies: # 'JSONAPI::ActiveRelationRetrieval' - A configurable retrieval strategy # 'JSONAPI::ActiveRelationRetrievalV09' - Retrieves resources using the v0.9.x approach. This uses rails' - # `includes` method to retrieve related models. This requires overriding the `records_for` method on the resource - # to control filtering of included resources. - # 'JSONAPI::ActiveRelationRetrievalV10' - Retrieves resources using the v0.10.x approach + # `includes` method to retrieve related models. This requires overriding the `records_for` method on the + # resource to control filtering of included resources. + # 'JSONAPI::ActiveRelationRetrievalV10' - Retrieves resources using the v0.10.x approach. While this is mostly + # equivalent to using the default JSONAPI::ActiveRelationRetrieval strategy with the + # `default_find_related_through` and `default_find_related_through_polymorphic` options set to `:primary`, + # it does perform a two phased query to retrieve resources like v0.10.x. did and is therefore less efficient. # Custom - Specify the a custom retrieval strategy module name as a string # :none # :self