class Onsi::Params

Used to handle parsing JSON-API formated params

@example

class PeopleController < ApplicationController
  include Onsi::Controller

  def create
    attributes = Onsi::Param.parse(
      params,
      [:first_name, :last_name],
      [:team]
    )
    render_resource Person.create!(attributes.flatten)
  end
end

Attributes

attributes[R]

The attributes for the params.

@return [ActionController::Parameters]

relationships[R]

The relationships for the params.

@return [Hash]

Public Class Methods

new(attributes, relationships) click to toggle source

Create a new Params instance.

@param attributes [ActionController::Parameters] The attributes

@param relationships [Hash] Flattened relationships hash

@note Should not be created directly. Use .parse or .parse_json

@private

# File lib/onsi/params.rb, line 130
def initialize(attributes, relationships)
  @attributes = attributes
  @relationships = relationships
end
parse(params, attributes = [], relationships = []) click to toggle source

Parse a JSON-API formatted params object.

@param params [ActionController::Parameters] The parameters to parse.

@param attributes [Array<String, Symbol>] The whitelisted attributes.

@param relationships [Array<String, Symbol>] The whitelisted relationships.

Should be the key for the relationships name.

@return [Params] The new params object.

# File lib/onsi/params.rb, line 74
def parse(params, attributes = [], relationships = [])
  parser = Onsi::ParamsParser.new(params, attributes, relationships)
  results = parser.parse!
  new(
    results.attributes,
    results.relationships
  )
end
parse_json(body, attributes = [], relationships = []) click to toggle source

Parse a JSON-API formatted JSON object.

@param body [String, read] The parameters to parse.

@param attributes [Array<String, Symbol>] The whitelisted attributes.

@param relationships [Array<String, Symbol>] The whitelisted relationships.

Should be the key for the relationships name.

@return [Onsi::Params] The new params object.

# File lib/onsi/params.rb, line 94
def parse_json(body, attributes = [], relationships = [])
  content = body.respond_to?(:read) ? body.read : body
  json = JSON.parse(content)
  params = ActionController::Parameters.new(json)
  parse(params, attributes, relationships)
end
safe_fetch(key, id) { |id| ... } click to toggle source
# File lib/onsi/params.rb, line 101
def safe_fetch(key, id)
  yield(id)
rescue ActiveRecord::RecordNotFound
  raise RelationshipNotFound.new("Can't find relationship #{key}", key)
end

Public Instance Methods

default(key, value) click to toggle source

Set a default value for attributes.

This value will only be used if the key is missing from the passed attributes

@param key [String, Symbol] The key to set a default on.

@param value [Any, call] The default value.

If the object responds to call (Lambda) it will be called when
parsing attributes

@example

params.default(:missing, -> { :foo })
subject.flatten[:missing]
# => :foo
# File lib/onsi/params.rb, line 234
def default(key, value)
  @attrs_hash = nil
  defaults[key.to_sym] = value
end
fetch(key, default = nil) click to toggle source

Fetch a value from the attributes or return the passed default value

@param key [String, Symbol] The key to fetch.

@param default [Any] The default value if the attribute doesn't exist.

@return [Any]

# File lib/onsi/params.rb, line 151
def fetch(key, default = nil)
  attrs_hash[key] || default
end
flatten() click to toggle source

Flatten an merge the attributes & relationships into one hash.

@return [Hash] The flattened attributes and relationships

# File lib/onsi/params.rb, line 139
def flatten
  @flattened ||= attrs_hash.to_h.merge(relationships.to_h).with_indifferent_access
end
require(key) click to toggle source

Make an attributes key required.

@param key [String, Symbol] The key of the attribute to require.

@raise [MissingReqiredAttribute] The value you have required isn't present

@return [Any] The value for the attribute

# File lib/onsi/params.rb, line 163
def require(key)
  value = attrs_hash[key]
  if value.nil?
    raise MissingReqiredAttribute.new("Missing attribute #{key}", key)
  end

  value
end
require_path(key_path) click to toggle source
# File lib/onsi/params.rb, line 172
def require_path(key_path)
  value = flatten.dig(*key_path.split('/'))
  if value.nil?
    raise MissingReqiredAttribute.new("Missing attribute at key_path #{key_path}", key_path)
  end

  value
end
safe_fetch(key, &block) click to toggle source

Handle finding a relationship's object.

@param key [String, Symbol] The key for the relationship

@raise [RelationshipNotFound] Thrown instead of an `ActiveRecord::RecordNotFound`

This allows the `Onsi::ErrorResponder` to build an appropriate response.

@example

params.safe_fetch(:person) do |id|
  Person.find(id)
end

@return [Any]

# File lib/onsi/params.rb, line 195
def safe_fetch(key, &block)
  self.class.safe_fetch(key, @relationships[key], &block)
end
transform(key, &block) click to toggle source

Perform a transform on the value

Any getter will run the value through the transform block.

@param key [String, Symbol] The key to transform.

@param block [Block] The block to perform the transform.

@note The values are memoized

@example

params.transform(:date) { |date| Time.parse(date) }

@return [Any]

# File lib/onsi/params.rb, line 214
def transform(key, &block)
  @attrs_hash = nil
  transforms[key.to_sym] = block
end

Private Instance Methods

attrs_hash() click to toggle source
# File lib/onsi/params.rb, line 249
def attrs_hash
  @attrs_hash ||= transform_attributes.merge(default_attributes).with_indifferent_access
end
default_attributes() click to toggle source
# File lib/onsi/params.rb, line 264
def default_attributes
  raw_attrs = attributes.to_h.symbolize_keys
  defaults.each_with_object({}) do |(key, value), object|
    next if raw_attrs.key?(key)

    if value.respond_to?(:call)
      object[key] = value.call
    else
      object[key] = value
    end
  end
end
defaults() click to toggle source
# File lib/onsi/params.rb, line 245
def defaults
  @defaults ||= {}
end
transform_attributes() click to toggle source
# File lib/onsi/params.rb, line 253
def transform_attributes
  attributes.to_h.each_with_object({}) do |(key, value), object|
    transform = transforms[key.to_sym]
    if transform
      object[key] = transform.call(value)
    else
      object[key] = value
    end
  end
end
transforms() click to toggle source
# File lib/onsi/params.rb, line 241
def transforms
  @transforms ||= {}
end