Class: JsonApiServer::RelationshipsBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/json_api_server/relationships_builder.rb

Overview

Description

Part of 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

Use this class to build relationships and included sections in serializers.

Examples

Relate, relate conditionally, or relate a collection. In this example, Publisher is added only if a condition is met (current user is an admin).

JsonApiServer::RelationshipsBuilder.new
  .relate('author', AuthorSerializer.new(@object.author))
  .relate_each('comments', @object.comments) {|c| CommentSerializer.new(c)}
  .relationships

# produces something like this if current user is an admin:
# {
#   "author"=>{
#      {data: {type: "authors", id: 6, attributes: {first_name: "john", last_name: "Doe"}}}
#   },
#   "publisher"=>{
#     {data: {type: "publishers", id: 1, attributes: {name: "abc"}}}
#   },
#   "comments"=>[
#     {data: {type: "comments", id: 1, attributes: {title: "a", comment: "b"}}},
#     {data: {type: "comments", id: 2, attributes: {title: "c", comment: "d"}}}
#   ]
# }

relationships can include all relationship data or it can reference data in included. To include and relate in one go, #include with the :relate option which takes a BaseSerializer#as_json_options hash.

builder = JsonApiServer::RelationshipsBuilder.new
  .include('author', AuthorSerializer.new(@object.author),
      relate: { include: [:relationship_data] })
  .include_each('comments', @object.comments) {|c| CommentSerializer.new(c) }

builder.relationships
# produces something like this if current user is an admin:
# {
#  "author" => {
#    {data: {id: 6, type: "authors"}}
#   },
#  "publisher" => {
#    {links: {self: 'http://.../publishers/1'}}
#   }
# }

builder.included
# produces something like this:
# [
#   {type: "author", id: 6, attributes: {first_name: "john", last_name: "Doe"}},
#   {type: "publisher", id: 1, attributes: {name: "abc"}},
#   {type: "comments", id: 1, attributes: {title: "a", comment: "b"}},
#   {type: "comments", id: 2, attributes: {title: "c", comment: "d"}}
# ]

Instance Method Summary collapse

Constructor Details

#initializeRelationshipsBuilder

Returns a new instance of RelationshipsBuilder.



67
68
69
70
# File 'lib/json_api_server/relationships_builder.rb', line 67

def initialize
  @relationships = {}
  @included = []
end

Instance Method Details

#include(type, serializer, **options) ⇒ Object

Add to included with this method.

Arguments:

  • type - (String) Relationship type/name.

  • serializer - (instance of serializer or something that responds to :as_json) - relationship content.

  • options - (Hash) -

    • :relate (Hash) - Optional. Add to relationships. BaseSerializer#as_json_options hash, i.e, { include: [:relationship_data] }.

i.e.,

# include and relate
JsonApiServer::RelationshipsBuilder.new(['comment.author'])
  .include('author', author_serializer,
     relate: {include: [:relationship_data]})

# or just include
JsonApiServer::RelationshipsBuilder.new(['author'])
   .include('author', author_serializer)


163
164
165
166
167
168
169
170
# File 'lib/json_api_server/relationships_builder.rb', line 163

def include(type, serializer, **options)
  merge_included(serializer)
  if options[:relate]
    serializer.as_json_options = options[:relate]
    relate(type, serializer)
  end
  self
end

#include_each(type, collection, **options) ⇒ Object

Add a collection to included with this method.

Arguments:

  • type - (String) Relationship type/name.

  • collection - Collection of objects to pass to block.

  • options - (Hash) -

    • :relate (Hash) - Optional. Add to relationships. BaseSerializer#as_json_options hash, i.e, { include: [:relationship_data] }.

  • block - Block that returns a serializer or something that repsonds_to as_json.

i.e.,

JsonApiServer::RelationshipsBuilder.new(['comments'])
   .include_each('comments', @comments) {|c| CommentSerializer.new(c)}


187
188
189
190
# File 'lib/json_api_server/relationships_builder.rb', line 187

def include_each(type, collection, **options)
  collection.each { |item| include(type, yield(item), options) }
  self
end

#includedObject

Returns included object. Includes added with #include, #include_if, #include_each.



86
87
88
89
# File 'lib/json_api_server/relationships_builder.rb', line 86

def included
  @included.uniq! if @included.respond_to?(:uniq!)
  @included
end

#relate(type, serializer) ⇒ Object

Add relationships with this method.

Arguments:

  • type - (String) Relationship type/name.

  • serializer - (instance of serializer or something that responds to :as_json) Content.

i.e.,

JsonApiServer::RelationshipsBuilder.new(['comment.author'])
  .relate('author', author_serializer)

# outputs something like...
# { 'author' => {
#  :data => {
#     :type => "people",
#    :id => 6,
#     :attributes => {:first_name=>"John", :last_name=>"Steinbeck"}
#     }
#   }
# }

JsonApiServer::RelationshipsBuilder.new(['comment.author'])
   .relate('author', author_serializer)

# outputs something like...
# { 'author' => {
#  :data => {
#     :type => "people",
#    :id => 6,
#     :attributes => {:first_name=>"John", :last_name=>"Steinbeck"}
#     }
#   }
# }


124
125
126
127
# File 'lib/json_api_server/relationships_builder.rb', line 124

def relate(type, serializer)
  merge_relationship(type, serializer)
  self
end

#relate_each(type, collection) ⇒ Object

Add a collection to relationships with this method.

Arguments:

  • type - (String) Relationship type/name.

  • collection - Collection of objects to pass to serializer.

  • block - Block that returns a serializer or something that repsonds_to as_json.

i.e.,

JsonApiServer::RelationshipsBuilder.new(['comments'])
  .relate_each('comments', @comments) { |c| CommentSerializer.new(c) }


140
141
142
143
# File 'lib/json_api_server/relationships_builder.rb', line 140

def relate_each(type, collection)
  collection.each { |item| relate(type, yield(item)) }
  self
end

#relationshipsObject

Returns relationships object. Relationships added with #relate, #relate_if, #relate_each and #include (with :relate option).



74
75
76
77
78
79
80
81
82
# File 'lib/json_api_server/relationships_builder.rb', line 74

def relationships
  @relationships.each do |k, v|
    if v.respond_to?(:uniq!)
      v.uniq!
      @relationships[k] = v.first if v.length == 1
    end
  end
  @relationships
end