class Fields::Serializer::FieldsTree

A class to store a tree structure of a model klass, its attributes and associations.

Attributes

associations[R]
fields[R]
klass[R]

Public Class Methods

new(klass) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 11
def initialize(klass)
  @klass        = klass
  @fields       = []
  @associations = {}
end

Public Instance Methods

merge!(join_field) click to toggle source

Adds a new field (json api notation) to the tree structure:

user_tree.notation
  #=> [:name, :surname, { subjects: [:title, { posts: { comments: :count } }], followers: :nickname }]

user_tree.merge!("subjects.posts.date").notation
  #=> [:name, :surname, { subjects: [:title, { posts: [{ comments: :count }, :date] }], followers: :nickname }]
# File lib/fields/serializer/fields_tree.rb, line 30
def merge!(join_field)
  return self if join_field.blank?
  parent, rest = join_field.to_s.split(".", 2)
  rest.present? ? add_association!(parent, rest) : add_field!(parent)
  self
end
notation() click to toggle source

Return the tree structure in Rails includes notation including both associations and fields

user_tree.notation
  #=> [:name, :surname, { subjects: [:title, { posts: :comments }], followers: :nickname }]
# File lib/fields/serializer/fields_tree.rb, line 42
def notation
  return associations_to_notation.presence if fields.blank?
  if associations.present?
    fields.dup << associations_to_notation
  else
    fields.one? ? fields.first.dup : fields.dup
  end
end
presence() click to toggle source

Self if any fields or associations. Nil otherwise

# File lib/fields/serializer/fields_tree.rb, line 18
def presence
  self if fields.present? || associations.present?
end
to_includes() click to toggle source

Return the tree structure in Rails includes notation including only associations

user_tree.notation
  #=> [{ subjects: { posts: :comments }}, :followers]
# File lib/fields/serializer/fields_tree.rb, line 56
def to_includes
  to_includes = associations.inject([]) do |result, (association_name, association_tree)|
    association_includes = association_tree.to_includes
    if association_includes.present?
      add_association_includes_to_includes!(result, association_name, association_includes)
    else
      add_association_to_includes!(result, association_name)
    end
  end.presence
  Array.wrap(to_includes).one? ? to_includes.first : to_includes
end
to_s() click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 68
def to_s
  notation.to_s
end

Private Instance Methods

add_association!(parent, rest) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 74
def add_association!(parent, rest)
  existing_association?(parent) ? merge_association!(parent, rest) : append_association!(parent, rest)
end
add_association_includes_to_includes!(includes, association_name, association_includes) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 78
def add_association_includes_to_includes!(includes, association_name, association_includes)
  new_has_entry = { association_name => association_includes }
  includes_hash = includes.find { |e| e.is_a?(Hash) }
  includes_hash ? includes_hash.merge!(new_has_entry) : (includes << new_has_entry)
  includes
end
add_association_to_includes!(includes, association_name) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 85
def add_association_to_includes!(includes, association_name)
  includes << association_name
end
add_field!(value) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 98
def add_field!(value)
  fields << value if new_field?(value)
end
append_association!(parent, rest) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 89
def append_association!(parent, rest)
  if association?(parent)
    nested_class       = klass.reflections[parent].klass
    nested_fields_tree = FieldsTree.new(nested_class).merge!(rest).presence
    new_association    = { parent => nested_fields_tree } if nested_fields_tree
    associations.merge!(new_association) if new_association
  end
end
association?(value) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 102
def association?(value)
  klass.reflections.key?(value)
end
associations_to_notation() click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 106
def associations_to_notation
  associations.inject({}) do |result, (k, v)|
    result.merge!(k => v.notation)
  end
end
existing_association?(value) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 112
def existing_association?(value)
  !!associations[value]
end
existing_field?(value) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 116
def existing_field?(value)
  fields.include?(value)
end
merge_association!(key, fields) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 120
def merge_association!(key, fields)
  associations[key].merge!(fields)
end
new_field?(value) click to toggle source
# File lib/fields/serializer/fields_tree.rb, line 124
def new_field?(value)
  !existing_field?(value) && !association?(value)
end