class Onsi::Resource

The wrapper for generating a object

@author Maddie Schipper @since 1.0.0

Constants

ATTRIBUTES_KEY

Root object attributes key

@private

DATA_KEY

Root object data key

@private

ID_KEY

Root object id key

@private

INCLUDED_KEY

Root object included key

@private

META_KEY

Metadata key

@private

RELATIONSHIPS_KEY

Root object relationships key

@private

TYPE_KEY

Root object type key

@private

Attributes

includes[R]

The includes for the object.

@return [Array<Onsi::Includes>]

object[R]

The backing object.

@note MUST include Onsi::Model

@return [Any] The object to be rendered by the resource.

version[R]

The version to render.

@return [Symbol]

Public Class Methods

as_resource(resource, version) click to toggle source

Convert an object into a Onsi::Resource

@param resource [Onsi::Resource, Enumerable, ActiveRecord::Base] The

object to be converted.
- If a Onsi::Resource is passed it will be directly returned.
- If an Enumerable is passed #map will be called and .as_resource will
  be recursivly called for each object.
- If any other object is passed it will be wrapped in a Onsi::Resource

@param version [Symbol] The version of the resource. `:v1`

@return [Onsi::Resource, Array<Onsi::Resource>]

# File lib/onsi/resource.rb, line 71
def as_resource(resource, version)
  case resource
  when Onsi::Resource
    resource
  when Onsi::Paginate::Result
    as_resource(resource.query, version)
  when Enumerable
    resource.map { |res| as_resource(res, version) }
  else
    Onsi::Resource.new(resource, version)
  end
end
new(object, version = nil, includes: nil) click to toggle source

Create a new resouce.

@param object [Any] The resource backing object.

@param version [Symbol] The version to render. Can be nil. If nil is

passed the DEFAULT_API_VERSION will be used.

@note The object MUST be a single object that includes Onsi::Model

@note The includes MUST be an array of Onsi::Include objects.

@return [Onsi::Resource] The new resource

# File lib/onsi/resource.rb, line 152
def initialize(object, version = nil, includes: nil)
  @object  = object
  @version = version || Model::DEFAULT_API_VERSION
  @includes = includes
  validate!
end
render(resource, version) click to toggle source

Render a resource to JSON

@param resource (see .as_resource)

@param version [Symbol] The version to render as. `:v1`

@return [Hash] The rendered resource as a hash ready to be converted

to JSON.
# File lib/onsi/resource.rb, line 93
def render(resource, version)
  resources = as_resource(resource, version)
  {}.tap do |root|
    root[DATA_KEY] = resources.as_json
    included = all_included(resources)
    if included.any?
      root[INCLUDED_KEY] = included
    end
    root[META_KEY] = {}.tap do |meta|
      meta[:count] = resources.count if resources.respond_to?(:count)
      if resource.is_a?(Onsi::Paginate::Result)
        meta[:pagination] = resource.params
      end
    end
  end
end

Private Class Methods

all_included(resources) click to toggle source
# File lib/onsi/resource.rb, line 112
def all_included(resources)
  Array(resources).map(&:flat_includes).flatten.uniq do |res|
    "#{res[TYPE_KEY]}-#{res[ID_KEY]}"
  end
end

Public Instance Methods

as_json(_opts = {}) click to toggle source

Creates a raw JSON object.

@return [Hash]

# File lib/onsi/resource.rb, line 163
def as_json(_opts = {})
  {}.tap do |root|
    root[TYPE_KEY] = type
    root[ID_KEY]   = object_identifier
    root[ATTRIBUTES_KEY] = generate_attributes
    append_relationships(root)
    append_meta(root)
    append_includes(root)
  end
end
flat_includes() click to toggle source

Flat includes

@private

# File lib/onsi/resource.rb, line 186
def flat_includes
  rendered_includes.values.map { |root| root[DATA_KEY] }.flatten
end
rendered_includes() click to toggle source

All rendered includes

@private

# File lib/onsi/resource.rb, line 178
def rendered_includes
  @rendered_includes ||= perform_render_includes
end

Private Instance Methods

append_includes(root) click to toggle source
# File lib/onsi/resource.rb, line 224
def append_includes(root)
  includes = generate_includes
  return unless includes.any?

  root[RELATIONSHIPS_KEY] ||= {}
  root[RELATIONSHIPS_KEY].merge!(includes)
end
append_meta(root) click to toggle source
# File lib/onsi/resource.rb, line 217
def append_meta(root)
  meta = generate_metadata
  return unless meta.any?

  root[META_KEY] = meta
end
append_relationships(root) click to toggle source
# File lib/onsi/resource.rb, line 210
def append_relationships(root)
  relationships = generate_relationships
  return unless relationships.any?

  root[RELATIONSHIPS_KEY] = relationships
end
generate_attributes() click to toggle source
# File lib/onsi/resource.rb, line 232
def generate_attributes
  object.class.api_renderer(version, nil, for_render: true).render_attributes(object)
end
generate_includes() click to toggle source
# File lib/onsi/resource.rb, line 244
def generate_includes
  {}.tap do |root|
    rendered_includes.each do |key, values|
      included = values[DATA_KEY]
      case included
      when Array
        root[key] = {}.tap do |subobj|
          subobj[DATA_KEY] = included.map do |inc|
            {
              TYPE_KEY => inc[TYPE_KEY],
              ID_KEY => inc[ID_KEY]
            }
          end
        end
      when Hash
        root[key] = { DATA_KEY => { TYPE_KEY => included[TYPE_KEY], ID_KEY => included[ID_KEY] } }
      end
    end
  end
end
generate_metadata() click to toggle source
# File lib/onsi/resource.rb, line 240
def generate_metadata
  object.class.api_renderer(version, nil, for_render: true).render_metadata(object)
end
generate_relationships() click to toggle source
# File lib/onsi/resource.rb, line 236
def generate_relationships
  object.class.api_renderer(version, nil, for_render: true).render_relationships(object)
end
object_identifier() click to toggle source
# File lib/onsi/resource.rb, line 201
def object_identifier
  attr = object.class.api_renderer(version, nil, for_render: true).id_attr
  object.send(attr).to_s
end
perform_render_includes() click to toggle source
# File lib/onsi/resource.rb, line 265
def perform_render_includes
  included = includes&.load_included
  {}.tap do |root|
    Hash(included).each do |key, results|
      root[key.to_s] = {}
      root[key.to_s][DATA_KEY] = render_included(results)
    end
  end
end
render_included(resources) click to toggle source
# File lib/onsi/resource.rb, line 275
def render_included(resources)
  Resource.as_resource(resources, version).as_json
end
type() click to toggle source
# File lib/onsi/resource.rb, line 206
def type
  object.class.api_renderer(version, nil, for_render: true).type || object.class.name.underscore
end
validate!() click to toggle source
# File lib/onsi/resource.rb, line 192
def validate!
  unless object.class.included_modules.include?(Onsi::Model)
    raise InvalidResourceError, "Trying to render a #{object.class.name}. But it doesn't include Onsi::Model"
  end
  if includes.present? && !includes.is_a?(Onsi::Includes)
    raise InvalidResourceError, "Included resources in #{self} is not a Onsi::Includes"
  end
end