RSpecでredirectするとヘッダーの設定が無視される

Rails4 + RSpec3 のrequests specでredirect後の処理を検証したい時、以下コードのようにheaders部分にIPアドレスを指定しても無視されてしまう。(ちなみにCapybaraだとセッションの検査ができなかったのでできればrspecで検査したいという状況だった)

before do
  params = {}
  headers = { 'REMOTE_ADDR' => '192.168.0.1' }
  get_via_redirect photos_url, params, headers
end

解決方法の結論

実際にIPアドレスを取得するのに使っているメソッド、例えばActionDispatch::Request#remote_ip にmockを設定すればよい。

before do
  params = {}

  allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return('192.168.0.1')

  get_via_redirect photos_url, params, headers
end

調べた

どう考えてもリダイレクト先でヘッダーの指定が無視されているので、コードを追ってみた

以下のように、get_via_redirectやpost_via_redirectを呼ぶとrequest_via_redirectが呼び出される

https://github.com/rails/rails/blob/v4.2.7.1/actionpack/lib/action_dispatch/testing/integration.rb#L100-L102

# Performs a GET request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
def get_via_redirect(path, parameters = nil, headers_or_env = nil)
  request_via_redirect(:get, path, parameters, headers_or_env)
end

呼び出し先のrequest_via_redirectを見ると、follw_redirect!はheaders_or_envを渡さずに呼び出される(この時点でヘッダーの情報は無視される)

https://github.com/rails/rails/blob/v4.2.7.1/actionpack/lib/action_dispatch/testing/integration.rb#L92-L96

# Performs a request using the specified method, following any subsequent
# redirect. Note that the redirects are followed until the response is
# not a redirect--this means you may run into an infinite loop if your
# redirect loops back to itself.
def request_via_redirect(http_method, path, parameters = nil, headers_or_env = nil)
  process(http_method, path, parameters, headers_or_env)
  follow_redirect! while redirect?
  status
end

follow_redirect!の中では、ただ単にリダイレクト先のURLをparamsやheadersを付けずにgetしてるだけ。

https://github.com/rails/rails/blob/v4.2.7.1/actionpack/lib/action_dispatch/testing/integration.rb#L82-L86

def follow_redirect!
  raise "not a redirect! #{status} #{status_message}" unless redirect?
  get(response.location)
  status
end

したがって、get_via_redirectをすると、ヘッダーの情報が消える。


コメントを残す