Class: Schemable::IncludedSchemaGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/schemable/included_schema_generator.rb

Overview

The IncludedSchemaGenerator class is responsible for generating the ‘included’ part of a JSON:API compliant response. This class generates schemas for related resources that should be included in the response.

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model_definition) ⇒ IncludedSchemaGenerator

Initializes a new IncludedSchemaGenerator instance.

Examples:

generator = IncludedSchemaGenerator.new(model_definition)

Parameters:

  • model_definition (ModelDefinition)

    The model definition to generate the schema for.



15
16
17
18
19
# File 'lib/schemable/included_schema_generator.rb', line 15

def initialize(model_definition)
  @model_definition = model_definition
  @schema_modifier = SchemaModifier.new
  @relationships = @model_definition.relationships
end

Instance Attribute Details

#model_definitionObject (readonly)

Returns the value of attribute model_definition.



7
8
9
# File 'lib/schemable/included_schema_generator.rb', line 7

def model_definition
  @model_definition
end

#relationshipsObject (readonly)

Returns the value of attribute relationships.



7
8
9
# File 'lib/schemable/included_schema_generator.rb', line 7

def relationships
  @relationships
end

#schema_modifierObject (readonly)

Returns the value of attribute schema_modifier.



7
8
9
# File 'lib/schemable/included_schema_generator.rb', line 7

def schema_modifier
  @schema_modifier
end

Instance Method Details

#generate(expand: false, relationships_to_exclude_from_expansion: []) ⇒ Hash

Note:

Make sure to provide the names correctly in string format and pluralize them if necessary. For example, if you have a relationship named ‘applicant’, and an applicant has association named ‘identity’, you should provide ‘identities’ as the names of the relationship to exclude from expansion. In this case, the included schema of the applicant will not include the identity relationship.

Generates the ‘included’ part of the JSON:API response. It iterates over each relationship type (belongs_to, has_many) and for each relationship, it prepares a schema. If the ‘expand’ option is true, it also includes the relationships of the related resource in the schema. In that case, the ‘addition_to_included’ relationships are also included in the schema unless they are excluded from expansion.

Examples:

schema = generator.generate(expand: true, relationships_to_exclude_from_expansion: ['some_relationship'])

Parameters:

  • expand (Boolean) (defaults to: false)

    Whether to include the relationships of the related resource in the schema.

  • relationships_to_exclude_from_expansion (Array) (defaults to: [])

    The relationships to exclude from the schema.

Returns:

  • (Hash)

    The generated schema.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/schemable/included_schema_generator.rb', line 38

def generate(expand: false, relationships_to_exclude_from_expansion: [])
  return {} if @relationships.blank?
  return {} if @relationships == { belongs_to: {}, has_many: {} }

  definitions = []

  %i[belongs_to has_many addition_to_included].each do |relation_type|
    next if @relationships[relation_type].blank?

    definitions << @relationships[relation_type].values
  end

  definitions.flatten!

  included_schemas = definitions.map do |definition|
    next if relationships_to_exclude_from_expansion.include?(definition.model_name)

    if expand
      definition_relations = definition.relationships[:belongs_to].values.map(&:model_name) + definition.relationships[:has_many].values.map(&:model_name)
      relations_to_exclude = []
      definition_relations.each do |relation|
        relations_to_exclude << relation if relationships_to_exclude_from_expansion.include?(relation)
      end

      prepare_schema_for_included(definition, expand:, relationships_to_exclude_from_expansion: relations_to_exclude)
    else
      prepare_schema_for_included(definition)
    end
  end

  schema = {
    included: {
      type: :array,
      items: {
        anyOf: included_schemas.compact_blank
      }
    }
  }

  @schema_modifier.add_properties(schema, @model_definition.additional_response_included, 'included.items') if @model_definition.additional_response_included.present?

  schema
end

#prepare_schema_for_included(model_definition, expand: false, relationships_to_exclude_from_expansion: []) ⇒ Hash

Prepares the schema for a related resource to be included in the response. It generates the attribute and relationship schemas for the related resource and combines them into a single schema.

Examples:

included_schema = generator.prepare_schema_for_included(related_model_definition, expand: true, relationships_to_exclude_from_expansion: ['some_relationship'])

Parameters:

  • model_definition (ModelDefinition)

    The model definition of the related resource.

  • expand (Boolean) (defaults to: false)

    Whether to include the relationships of the related resource in the schema.

  • relationships_to_exclude_from_expansion (Array) (defaults to: [])

    The relationships to exclude from the schema.

Returns:

  • (Hash)

    The generated schema for the related resource.



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/schemable/included_schema_generator.rb', line 93

def prepare_schema_for_included(model_definition, expand: false, relationships_to_exclude_from_expansion: [])
  attributes_schema = AttributeSchemaGenerator.new(model_definition).generate
  relationships_schema = RelationshipSchemaGenerator.new(model_definition).generate(relationships_to_exclude_from_expansion:, expand:)

  {
    type: :object,
    properties: {
      type: { type: :string, default: model_definition.model_name },
      id: { type: :string },
      attributes: attributes_schema
    }.merge!(relationships_schema.blank? ? {} : { relationships: relationships_schema })
  }.compact_blank
end