app/api/locomotive/api/middlewares/params_decoder_middleware.rb
# Issue here: https://github.com/ruby-grape/grape/issues/1028
# Solution: https://github.com/typhoeus/typhoeus/blob/master/lib/rack/typhoeus/middleware/params_decoder/helper.rb
#
# MIT License Paul Dix, David Balatero, Hans Hasselberg
#
module Locomotive
module API
module Middlewares
class ParamsDecoderMiddleware
def initialize(app)
@app = app
end
def call(env)
request = Rack::Request.new(env)
decode(request.params).each_pair { |k, v| update_params request, k, v }
@app.call(env)
end
private
# Persist params change in environment. Extracted from:
# https://github.com/rack/rack/blob/master/lib/rack/request.rb#L243
def update_params(req, k, v)
found = false
if req.GET.has_key?(k)
found = true
req.GET[k] = v
end
if req.POST.has_key?(k)
found = true
req.POST[k] = v
end
unless found
req.GET[k] = v
end
end
def decode!(hash)
return hash unless hash.is_a?(Hash)
hash.each_pair do |key,value|
if value.is_a?(Hash)
decode!(value)
hash[key] = convert(value)
end
end
hash
end
def decode(hash)
decode!(hash.dup)
end
# Checks if Hash is an Array encoded as a Hash.
# Specifically will check for the Hash to have this
# form: {'0' => v0, '1' => v1, .., 'n' => vN }
#
# @param hash [Hash]
#
# @return [Boolean] True if its a encoded Array, else false.
def encoded?(hash)
return false if hash.empty?
if hash.keys.size > 1
keys = hash.keys.map{|i| i.to_i if i.respond_to?(:to_i)}.sort
keys == hash.keys.size.times.to_a
else
hash.keys.first =~ /0/
end
end
# If the Hash is an array encoded by typhoeus an array is returned
# else the self is returned
#
# @param hash [Hash] The Hash to convert into an Array.
#
# @return [Arraya/Hash]
def convert(hash)
if encoded?(hash)
hash.sort{ |a, b| a[0].to_i <=> b[0].to_i }.map { |key, value| value }
else
hash
end
end
end
end
end
end