Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
module Api::ControllerHelpers
extend ActiveSupport::Concern
included do
include InstanceMethods
before_action :prepare_restful_params
end
module InstanceMethods
def prepare_restful_params
@fields, @include = prepare_for_fields_and_include(
fields_param: process_param_as_array(params[:fields]),
include_param: process_param_as_array(params[:include]),
) unless debug_mode?
end
# @example
# prepare_for_fields_and_include(
# fields_param: ['name', 'articles.title', 'articles.url'],
# include_param: ['articles', 'articles.image']
# )
# #=>
# # [
# # [:id, :name],
# # {
# # articles: {
# # fields: [:id, :title],
# # image: {
# # fields: [:id, :url]
# # }
# # }
# # }
# # ]
def prepare_for_fields_and_include(fields_param: [], include_param: [])
fields_param = fields_param.map{ |v| v.split('.').map(&:to_sym) }
include_param = include_param.map{ |v| v.split('.').map(&:to_sym) }
include = include_param.sort_by(&:size).inject({}) do |include, associations|
hash = include
associations.each_with_index do |association, i|
if i == associations.size - 1
hash[association] = {}
else
hash = hash[association]
if hash.nil?
raise Api::ImplicitIncludeError.new(associations[0..i])
end
end
end
include
end
fields = fields_param.select { |f| f.size == 1 }.flatten
nested = fields_param.select { |f| f.size > 1 }
fields << :id unless fields.include?(:id)
nested.each do |f|
associations, field = f[0..-2], f[-1]
hash = include.dig(*associations)
if hash.nil?
raise Api::UnincludedFieldError.new(field, associations)
end
hash[:fields] ||= [:id]
hash[:fields] << f.last unless hash[:fields].include?(f.last)
end
return fields, include
end
# To accept both comma-separated array and brackets array.
# And treat nil as empty array.
#
# comma-separated array: fields=foo,bar,baz
# brackets array: fields[]=foo&fields[]=bar&fields[]=baz
def process_param_as_array(param)
case param
when nil
[]
when Array
param
when String
param.split(',')
end
end
def debug_mode?
params[:debug].to_b && !Rails.env.production?
end
def preload_for(rel)
Api::Preloader.preload_for(rel, @fields, @include)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.