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をすると、ヘッダーの情報が消える。