class JsonApiServer::Include
Description:¶ ↑
Handles include parameters per JSON API spec jsonapi.org/format/#fetching-includes.
An endpoint may support an include request parameter to allow the client to customize which related resources should be returned.
ie., GET /articles/1?include=comments,comment.author,tags HTTP/1.1
This class (1) whitelists include params, (2) maintains an array of permitted inclusions, and (3) generates a sub-query if eagerloading is configured for inclusions.
Usage:¶ ↑
An inclusion request looks like:
/topics?include=author,comment.author,comments
It is converted to an array of relationships:
['author', 'comment.author', 'comments']
Includes are whitelisted with a configuration that looks like:
{ {'author': -> { includes(:author) }}, {'comments': -> { includes(:comments) }}, 'comment.author' }
In this example, author, comments, and comment.author are allowed includes. If an unsupported include is requested, a JsonApiServer::BadRequest
exception is raised which renders a 400 error.
A proc/lambda can be specified to eagerload relationships. Be careful, to date, there is no way to apply limits to :includes.
Example:¶ ↑
permitted = { {'author': -> { includes(:author) }}, {'comments': -> { includes(:comments) }}, 'comment.author' } # create instance include = JsonApiServer::Include.new(request, Topic, permitted) # merge into master query recent_topics = Topic.recent.merge(include.query) # use in serializers class CommentSerializer < JsonApiServer::ResourceSerializer def relationships if relationship?('comment.author') # relationship? is a helper methods in serializers. #... end end end
Note:¶ ↑
JsonApiServer::Builder
class provides an easier way to use this class.
Attributes
ActiveRecord::Base model passed in constructor.
Query parameters from request
.
Include
configs passed in constructor.
ActionDispatch::Request passed in constructor.
Public Class Methods
Arguments:
-
request
- ActionDispatch::Request -
model
(ActiveRecord::Base) - Model to append queries to. -
permitted
(Array) - Permitted inclusions. To eagerload the relationship, pass a proc:
Example:¶ ↑
Eagerloads author, comments, comments -> authors.
[ {'author': -> { includes(:author) }}, {'comments': -> { includes(:comments) }}, {'comments.author': -> {includes(comments: :author) }}, 'publisher.addresses' ]
# File lib/json_api_server/include.rb, line 92 def initialize(request, model, permitted = []) @request = request @model = model @permitted = permitted.is_a?(Array) ? permitted : [] @params = request.query_parameters end
Public Instance Methods
Array of include params from the request.
Examples¶ ↑
include=comments becomes ['comments'] include=comments.author,tags becomes ['comments.author', 'tags']
# File lib/json_api_server/include.rb, line 116 def include_params @include_params ||= begin params[:include].present? ? params[:include].split(',').map!(&:strip) : [] end end
Array of whitelisted include params. Raises JsonApiServer::BadRequest
if any include_params
is not whitelisted.
Examples¶ ↑
include=comments becomes ['comments'] include=comments.author,tags becomes ['comments.author', 'tags']
# File lib/json_api_server/include.rb, line 106 def includes include_params.select { |i| config_for(i).present? } end
Returns an ActiveRecord::Relation object (a query fragment). Returns nil if no eagerloading is configured.
# File lib/json_api_server/include.rb, line 124 def relation @relation ||= begin additions = false # TODO: merge! has unexpected results. frag = include_params.reduce(model.all) do |result, inclusion| config = config_for(inclusion) query = config.respond_to?(:keys) ? config.values.first : nil unless query.nil? additions = true result = result.merge(query) end result end additions ? frag : nil end end
Protected Instance Methods
Returns config. Raises JsonApiServer::BadRequest
if inclusion is not whitelisted.
# File lib/json_api_server/include.rb, line 146 def config_for(inclusion) config = permitted.find do |v| inc = inclusion.to_s v.respond_to?(:keys) ? v.keys.first.to_s == inc : v.to_s == inc end if config.nil? msg = I18n.t('json_api_server.render_400.inclusion', param: inclusion) raise JsonApiServer::BadRequest, msg end config end