jsonapi-serializers icon indicating copy to clipboard operation
jsonapi-serializers copied to clipboard

Optimize lookups of relationships where ID is sufficient

Open fotinakis opened this issue 10 years ago • 5 comments
trafficstars

Consolidating issues:

  • https://github.com/fotinakis/jsonapi-serializers/issues/23 Add include id relation only option and smart related link behavior based on that
  • https://github.com/fotinakis/jsonapi-serializers/issues/29 Lazily-evaluated relationships

We need a mechanism to reference post.author_id rather than author.id when only finding the ID for relationship data and links. Right now, we naively always reference the .id method which, in the ActiveRecord world, forces a load of that record (unless it has been preloaded via .includes(:author) when loading the parent).

A few options:

  • Automatically try the relationship's <relationship name>_id method and fallback to the object's id method.
  • Provide a way to hint at the relationship method name, like id_lookup: :author_id. This idea could be part of the above option.

fotinakis avatar Oct 13 '15 20:10 fotinakis

Could this not be done with Post.reflect_on_association(:author).association_foreign_key?

garrettlancaster avatar Jan 15 '16 21:01 garrettlancaster

jsonapi-serializers is not coupled at all to ActiveRecord at the moment, so no, not if we wanted to maintain that. We could potentially use those methods and have a fallback for the more generic case.

fotinakis avatar Jan 15 '16 22:01 fotinakis

Ah, I see. I suppose we could use the adapter pattern to solve the problem for users while maintaining jsonapi-serializers' independence. e.g. jsonapi-serializers-activerecord could register itself and override whatever smart defaults are provided for the generic case.

garrettlancaster avatar Jan 15 '16 22:01 garrettlancaster

Yup that could work. I also like the more lightweight solution of just duck-type checking if the methods exist and then falling back, since there's not a lot of other coupling we need to do so jsonapi-serializers-activerecord might be too heavyweight right now.

fotinakis avatar Jan 15 '16 22:01 fotinakis

This problem is particularly gruesome with e.g. Sequel, which eagerly typecasts entire records (as opposed to ActiveRecord's lazy typecasting). It gets pretty ugly when you need to include types and IDs for a tall and wide has_many collection.

I've been looking at JSONAPI::Serializer#has_one_relationship and JSONAPI::Serializer#has_many_relationship. It seems to me that there should be a hint passed to those methods when you only need an object "skeleton." Instead of JSONAPI::Serializer#evaluate_attr_or_block doing this:

object.send(attr_or_block)

I really want it to look for a hook in my (base) serializer that I've overridden to do this, for has_many skeletons:

def has_many_skeletons(attr)
  reflection = object.model.association_reflection(attr)
  klass = reflection.associated_class
  reflection.association_dataset_for(object).select(klass.primary_key).all
end

Or this, for has_one skeletons:

def has_one_skeleton(attr)
  reflection = object.model.association_reflection(attr)
  klass = reflection.associated_class
  reflection.association_dataset_for(object).select(klass.primary_key).first
end

You might be able to get crafty for has_one and avoid a query entirely for the simple cases:

def has_one_skeleton(attr)
  reflection = object.model.association_reflection(attr)
  klass, id = reflection.associated_class, object.send(reflection.default_key)
  klass.(klass.primary_key_hash(id))
end

I'll admit to getting a little lost in Sequel's association reflection documentation, so there might be better ways to accomplish the above.

mwpastore avatar Nov 14 '18 23:11 mwpastore