module ArSerializer::Serializer
Public Class Methods
_serialize(mixed_value_outputs, attributes, context, include_id, only = nil, except = nil)
click to toggle source
# File lib/ar_serializer/serializer.rb, line 57 def self._serialize(mixed_value_outputs, attributes, context, include_id, only = nil, except = nil) mixed_value_outputs.group_by { |v, _o| v.class }.each do |klass, value_outputs| next unless klass.respond_to? :_serializer_field_info models = value_outputs.map(&:first) value_outputs.each { |value, output| output[:id] = value.id } if include_id && klass.method_defined?(:id) if attributes.any? { |k, _| k == :* } all_keys = klass._serializer_field_keys.map(&:to_sym) - [:defaults] all_keys &= only.map(&:to_sym) if only all_keys -= except.map(&:to_sym) if except attributes = all_keys.map { |k| [k, {}] } + attributes.reject { |k, _| k == :* } end attributes.each do |name, sub_args| field_name = sub_args[:field_name] || name field = klass._serializer_field_info field_name raise ArSerializer::InvalidQuery, "No serializer field `#{field_name}`#{" namespaces: #{current_namespaces}" if current_namespaces} for #{klass}" unless field ActiveRecord::Associations::Preloader.new.preload models, field.includes if field.includes.present? end preloader_params = attributes.flat_map do |name, sub_args| field_name = sub_args[:field_name] || name klass._serializer_field_info(field_name).preloaders.map do |p| [p, sub_args[:params]] end end defaults = klass._serializer_field_info(:defaults) if defaults preloader_params += defaults.preloaders.map { |p| [p] } end preloader_values = preloader_params.compact.uniq.map do |key| preloader, params = key has_keyword = preloader.parameters.any? { |type, _name| %i[key keyreq keyrest].include? type } arity = preloader.arity.abs arguments = [models] if has_keyword arguments << context unless arity == 2 [key, preloader.call(*arguments, **(params || {}))] else arguments << context unless arity == 1 [key, preloader.call(*arguments)] end end.to_h if defaults preloadeds = defaults.preloaders.map { |p| preloader_values[[p]] } || [] value_outputs.each do |value, output| data = value.instance_exec(*preloadeds, context, {}, &defaults.data_block) output.update data end end attributes.each do |name, sub_arg| params = sub_arg[:params] sub_calls = [] column_name = sub_arg[:column_name] || name field_name = sub_arg[:field_name] || name info = klass._serializer_field_info field_name preloadeds = info.preloaders.map { |p| preloader_values[[p, params]] } || [] data_block = info.data_block value_outputs.each do |value, output| child = value.instance_exec(*preloadeds, context, **(params || {}), &data_block) if child.is_a?(Array) && child.all? { |el| el.is_a? ArSerializer::Serializable } output[column_name] = child.map do |record| data = {} sub_calls << [record, data] data end elsif child.respond_to? :ar_serializer_build_sub_calls sub_output, record_elements = child.ar_serializer_build_sub_calls record_elements.each { |o| sub_calls << o } output[column_name] = sub_output elsif child.is_a? ArSerializer::Serializable data = {} sub_calls << [child, data] output[column_name] = data else output[column_name] = child end end next if sub_calls.empty? sub_attributes = sub_arg[:attributes] || {} info.validate_attributes sub_attributes _serialize sub_calls, sub_attributes, context, include_id, info.only, info.except end end end
current_namespaces()
click to toggle source
# File lib/ar_serializer/serializer.rb, line 28 def self.current_namespaces Thread.current[:ar_serializer_current_namespaces] end
deep_with_indifferent_access(params)
click to toggle source
# File lib/ar_serializer/serializer.rb, line 143 def self.deep_with_indifferent_access params case params when Array params.map { |v| deep_with_indifferent_access v } when Hash params.transform_keys(&:to_sym).transform_values! do |v| deep_with_indifferent_access v end else params end end
parse_args(args, only_attributes: false)
click to toggle source
# File lib/ar_serializer/serializer.rb, line 156 def self.parse_args(args, only_attributes: false) attributes = [] params = nil column_name = nil field_name = nil (args.is_a?(Array) ? args : [args]).each do |arg| if arg.is_a?(Symbol) || arg.is_a?(String) attributes << [arg.to_sym, {}] elsif arg.is_a? Hash arg.each do |key, value| sym_key = key.to_sym if !only_attributes && sym_key == :field field_name = value elsif !only_attributes && sym_key == :as column_name = value elsif !only_attributes && %i[attributes query].include?(sym_key) attributes.concat parse_args(value, only_attributes: true) elsif !only_attributes && sym_key == :params params = deep_with_indifferent_access value else attributes << [sym_key, value == true ? {} : parse_args(value)] end end else raise ArSerializer::InvalidQuery, "Arg type missmatch(Symbol, String or Hash): #{arg}" end end return attributes if only_attributes { attributes: attributes, column_name: column_name, field_name: field_name, params: params || {} } end
serialize(model, query, context: nil, include_id: false, use: nil)
click to toggle source
# File lib/ar_serializer/serializer.rb, line 40 def self.serialize(model, query, context: nil, include_id: false, use: nil) with_namespaces use do attributes = parse_args(query)[:attributes] if model.is_a?(ArSerializer::Serializable) output = {} _serialize [[model, output]], attributes, context, include_id output else sets = model.to_a.map do |record| [record, {}] end _serialize sets, attributes, context, include_id sets.map(&:last) end end end
with_namespaces(namespaces) { || ... }
click to toggle source
# File lib/ar_serializer/serializer.rb, line 32 def self.with_namespaces(namespaces) namespaces_was = Thread.current[:ar_serializer_current_namespaces] Thread.current[:ar_serializer_current_namespaces] = namespaces yield ensure Thread.current[:ar_serializer_current_namespaces] = namespaces_was end