module FastJsonapi::ObjectSerializer

Constants

TRANSFORMS_MAPPING

Public Class Methods

new(resource, options = {}) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 30
def initialize(resource, options = {})
  process_options(options)

  @resource = resource
end

Public Instance Methods

hash_for_collection() click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 57
def hash_for_collection
  serializable_hash = {}

  data = []
  included = []
  fieldset = @fieldsets[self.class.record_type.to_sym]
  @resource.each do |record|
    data << self.class.record_hash(record, fieldset, @includes, @params)
    included.concat self.class.get_included_records(record, @includes, @known_included_objects, @fieldsets, @params) if @includes.present?
  end

  serializable_hash[:data] = data
  serializable_hash[:included] = included if @includes.present?
  serializable_hash[:meta] = @meta if @meta.present?
  serializable_hash[:links] = @links if @links.present?
  serializable_hash
end
hash_for_one_record() click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 45
def hash_for_one_record
  serializable_hash = { data: nil }
  serializable_hash[:meta] = @meta if @meta.present?
  serializable_hash[:links] = @links if @links.present?

  return serializable_hash unless @resource

  serializable_hash[:data] = self.class.record_hash(@resource, @fieldsets[self.class.record_type.to_sym], @includes, @params)
  serializable_hash[:included] = self.class.get_included_records(@resource, @includes, @known_included_objects, @fieldsets, @params) if @includes.present?
  serializable_hash
end
serializable_hash() click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 36
def serializable_hash
  if self.class.is_collection?(@resource, @is_collection)
    return hash_for_collection
  end

  hash_for_one_record
end
Also aliased as: to_hash
to_hash()
Alias for: serializable_hash

Private Instance Methods

add_relationship(relationship) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 229
def add_relationship(relationship)
  self.relationships_to_serialize = {} if relationships_to_serialize.nil?
  self.cachable_relationships_to_serialize = {} if cachable_relationships_to_serialize.nil?
  self.uncachable_relationships_to_serialize = {} if uncachable_relationships_to_serialize.nil?

  # TODO: Remove this undocumented option.
  #   Delegate the caching to the serializer exclusively.
  if relationship.cached
    cachable_relationships_to_serialize[relationship.name] = relationship
  else
    uncachable_relationships_to_serialize[relationship.name] = relationship
  end
  relationships_to_serialize[relationship.name] = relationship
end
attributes(*attributes_list, &block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 208
def attributes(*attributes_list, &block)
  attributes_list = attributes_list.first if attributes_list.first.class.is_a?(Array)
  options = attributes_list.last.is_a?(Hash) ? attributes_list.pop : {}
  self.attributes_to_serialize = {} if attributes_to_serialize.nil?

  # to support calling `attribute` with a lambda, e.g `attribute :key, ->(object) { ... }`
  block = attributes_list.pop if attributes_list.last.is_a?(Proc)

  attributes_list.each do |attr_name|
    method_name = attr_name
    key = run_key_transform(method_name)
    attributes_to_serialize[key] = Attribute.new(
      key: key,
      method: block || method_name,
      options: options
    )
  end
end
belongs_to(relationship_name, options = {}, &block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 254
def belongs_to(relationship_name, options = {}, &block)
  relationship = create_relationship(relationship_name, :belongs_to, options, block)
  add_relationship(relationship)
end
cache_options(cache_options) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 179
def cache_options(cache_options)
  # FIXME: remove this if block once deprecated cache_options are not supported anymore
  unless cache_options.key?(:store)
    # fall back to old, deprecated behaviour because no store was passed.
    # we assume the user explicitly wants new behaviour if he passed a
    # store because this is the new syntax.
    deprecated_cache_options(cache_options)
    return
  end

  self.cache_store_instance = cache_options[:store]
  self.cache_store_options = cache_options.except(:store)
end
compute_id_method_name(custom_id_method_name, id_method_name_from_relationship, polymorphic, serializer, block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 300
def compute_id_method_name(custom_id_method_name, id_method_name_from_relationship, polymorphic, serializer, block)
  if block.present? || serializer.is_a?(Proc) || polymorphic
    custom_id_method_name || :id
  else
    custom_id_method_name || id_method_name_from_relationship
  end
end
create_relationship(base_key, relationship_type, options, block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 263
def create_relationship(base_key, relationship_type, options, block)
  name = base_key.to_sym
  if relationship_type == :has_many
    base_serialization_key = base_key.to_s.singularize
    id_postfix = '_ids'
  else
    base_serialization_key = base_key
    id_postfix = '_id'
  end
  polymorphic = fetch_polymorphic_option(options)

  Relationship.new(
    owner: self,
    key: options[:key] || run_key_transform(base_key),
    name: name,
    id_method_name: compute_id_method_name(
      options[:id_method_name],
      "#{base_serialization_key}#{id_postfix}".to_sym,
      polymorphic,
      options[:serializer],
      block
    ),
    record_type: options[:record_type],
    object_method_name: options[:object_method_name] || name,
    object_block: block,
    serializer: options[:serializer],
    relationship_type: relationship_type,
    cached: options[:cached],
    polymorphic: polymorphic,
    conditional_proc: options[:if],
    transform_method: @transform_method,
    meta: options[:meta],
    links: options[:links],
    lazy_load_data: options[:lazy_load_data]
  )
end
deep_symbolize(collection) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 96
def deep_symbolize(collection)
  if collection.is_a? Hash
    collection.each_with_object({}) do |(k, v), hsh|
      hsh[k.to_sym] = deep_symbolize(v)
    end
  elsif collection.is_a? Array
    collection.map { |i| deep_symbolize(i) }
  else
    collection.to_sym
  end
end
deprecated_cache_options(cache_options) click to toggle source

FIXME: remove this method once deprecated cache_options are not supported anymore

# File lib/fast_jsonapi/object_serializer.rb, line 194
def deprecated_cache_options(cache_options)
  warn('DEPRECATION WARNING: `store:` is a required cache option, we will default to `Rails.cache` for now. See https://github.com/fast-jsonapi/fast_jsonapi#caching for more information.')

  %i[enabled cache_length].select { |key| cache_options.key?(key) }.each do |key|
    warn("DEPRECATION WARNING: `#{key}` is a deprecated cache option and will have no effect soon. See https://github.com/fast-jsonapi/fast_jsonapi#caching for more information.")
  end

  self.cache_store_instance = cache_options[:enabled] ? Rails.cache : nil
  self.cache_store_options = {
    expires_in: cache_options[:cache_length] || 5.minutes,
    race_condition_ttl: cache_options[:race_condition_ttl] || 5.seconds
  }
end
fetch_polymorphic_option(options) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 321
def fetch_polymorphic_option(options)
  option = options[:polymorphic]
  return false unless option.present?
  return option if option.respond_to? :keys

  {}
end
has_many(relationship_name, options = {}, &block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 244
def has_many(relationship_name, options = {}, &block)
  relationship = create_relationship(relationship_name, :has_many, options, block)
  add_relationship(relationship)
end
has_one(relationship_name, options = {}, &block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 249
def has_one(relationship_name, options = {}, &block)
  relationship = create_relationship(relationship_name, :has_one, options, block)
  add_relationship(relationship)
end
inherited(subclass) click to toggle source
Calls superclass method
# File lib/fast_jsonapi/object_serializer.rb, line 118
def inherited(subclass)
  super(subclass)
  subclass.attributes_to_serialize = attributes_to_serialize.dup if attributes_to_serialize.present?
  subclass.relationships_to_serialize = relationships_to_serialize.dup if relationships_to_serialize.present?
  subclass.cachable_relationships_to_serialize = cachable_relationships_to_serialize.dup if cachable_relationships_to_serialize.present?
  subclass.uncachable_relationships_to_serialize = uncachable_relationships_to_serialize.dup if uncachable_relationships_to_serialize.present?
  subclass.transform_method = transform_method
  subclass.data_links = data_links.dup if data_links.present?
  subclass.cache_store_instance = cache_store_instance
  subclass.cache_store_options = cache_store_options
  subclass.set_type(subclass.reflected_record_type) if subclass.reflected_record_type
  subclass.meta_to_serialize = meta_to_serialize
  subclass.record_id = record_id
  subclass.record_type_block = record_type_block
end
is_collection?(resource, force_is_collection = nil) click to toggle source

Detects a collection/enumerable

@return [TrueClass] on a successful detection

# File lib/fast_jsonapi/object_serializer.rb, line 112
def is_collection?(resource, force_is_collection = nil)
  return force_is_collection unless force_is_collection.nil?

  resource.is_a?(Enumerable) && !resource.respond_to?(:each_pair)
end
meta(meta_name = nil, &block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 259
def meta(meta_name = nil, &block)
  self.meta_to_serialize = block || meta_name
end
process_options(options) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 77
def process_options(options)
  @fieldsets = deep_symbolize(options[:fields].presence || {})
  @params = {}

  return if options.blank?

  @known_included_objects = Set.new
  @meta = options[:meta]
  @links = options[:links]
  @is_collection = options[:is_collection]
  @params = options[:params] || {}
  raise ArgumentError, '`params` option passed to serializer must be a hash' unless @params.is_a?(Hash)

  if options[:include].present?
    @includes = options[:include].reject(&:blank?).map(&:to_sym)
    self.class.validate_includes!(@includes)
  end
end
reflected_record_type() click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 134
def reflected_record_type
  return @reflected_record_type if defined?(@reflected_record_type)

  @reflected_record_type ||= begin
    name.split('::').last.chomp('Serializer').underscore.to_sym if name&.end_with?('Serializer')
  end
end
run_key_transform(input) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 154
def run_key_transform(input)
  if transform_method.present?
    input.to_s.send(*@transform_method).to_sym
  else
    input.to_sym
  end
end
serializer_for(name) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 308
def serializer_for(name)
  namespace = self.name.gsub(/()?\w+Serializer$/, '')
  serializer_name = "#{name.to_s.demodulize.classify}Serializer"
  serializer_class_name = namespace + serializer_name
  begin
    serializer_class_name.constantize
  rescue NameError
    raise NameError, "#{self.name} cannot resolve a serializer class for '#{name}'.  " \
                     "Attempted to find '#{serializer_class_name}'. " \
                     'Consider specifying the serializer directly through options[:serializer].'
  end
end
set_id(id_name = nil, &block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 171
def set_id(id_name = nil, &block)
  self.record_id = block || id_name
end
set_key_transform(transform_name) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 142
def set_key_transform(transform_name)
  self.transform_method = TRANSFORMS_MAPPING[transform_name.to_sym]

  # ensure that the record type is correctly transformed
  if record_type
    set_type(record_type)
  # TODO: Remove dead code
  elsif reflected_record_type
    set_type(reflected_record_type)
  end
end
set_record_type_block(&block) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 175
def set_record_type_block(&block)
  self.record_type_block = block
end
set_type(type_name) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 167
def set_type(type_name)
  self.record_type = run_key_transform(type_name)
end
use_hyphen() click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 162
def use_hyphen
  warn('DEPRECATION WARNING: use_hyphen is deprecated and will be removed from fast_jsonapi 2.0 use (set_key_transform :dash) instead')
  set_key_transform :dash
end
validate_includes!(includes) click to toggle source
# File lib/fast_jsonapi/object_serializer.rb, line 345
def validate_includes!(includes)
  return if includes.blank?

  parse_includes_list(includes).each_key do |include_item|
    relationship_to_include = relationships_to_serialize[include_item]
    warn(JSONAPI::Serializer::UnsupportedIncludeError.new(include_item, name)) unless relationship_to_include

    relationship_to_include.static_serializer if relationship_to_include # called for a side-effect to check for a known serializer class.
  end
end