Вы правы - метод headers
для ActionController::Request
возвращает экземпляр ActionController::Http::Headers
, который наследуется от Hash. Если мы взломаем источник, мы увидим это:
class Headers < ::Hash
extend ActiveSupport::Memoizable
def initialize(*args)
if args.size == 1 && args[0].is_a?(Hash)
super()
update(args[0])
else
super
end
end
def [](header_name)
if include?(header_name)
super
else
super(env_name(header_name))
end
end
private
# Converts a HTTP header name to an environment variable name.
def env_name(header_name)
"HTTP_#{header_name.upcase.gsub(/-/, '_')}"
end
memoize :env_name
end
Таким образом, при обращении к хэшу через []
, есть вторая проверка, чтобы увидеть, существует ли значение из env_name
(которое просто преобразует ключ в ключ и добавляет HTTP_
).
Вот почему вы не можете получить истинное значение из request.headers.include?('Authorization')
- include?
не переопределяется в подклассе для проверки как обычной, так и расширенной версии заголовка. Я полагаю, что вы могли бы последовать этому примеру и реализовать его самостоятельно так:
module ActionController
module Http
class Headers < ::Hash
def include?(header_name)
self[header_name].present?
end
end
end
end
Бросьте это в lib/extensions/action_controller.rb
или что-то еще, потребуйте его в environment.rb
, если это необходимо, и вам будет хорошо идти. Я бы порекомендовал просто изменить код вашего контроллера, чтобы использовать []
и present?
для проверки:)
Причина в том, что заголовки имеют префикс с префиксом HTTP_
, я полагаю, проистекает из Rack, промежуточного программного обеспечения Rails HTTP. Вероятно, он делает это, чтобы оставаться беспристрастным по отношению к делу, дополнительно добавляя HTTP_
, чтобы избежать конфликтов с другими входящими в окружение материалами, не являющимися заголовками.
Так что, да, немного волшебно, но не слишком сложно понять после просмотра источника, который я всегда рекомендую :) У Rails есть очень хороший источник, который я многому научился за эти годы.