Earlier today I began having an infuriating problem coming from assert_redirected_to. The tests were failing an error like the following:
test_index_user_not_login(Admin::ConfigurationControllerTest) [./test/ functional/admin/configuration_controller_test.rb:20]: response is not a redirection to all of the options supplied (redirection is <{:action=>"login", :controller=>"user"}>), difference: <{}>
Hrm I said. Difference is {} ? Shouldn’t that mean that there is no difference? I hit the web and found some references to this sort of problem, mostly involving absolute controller paths. I don’t use absolute controller paths very often, but tried the fix anyway. No dice. So I rolled up my sleeves and set up some breakpoints and got to debugging. The problem was in the following portion of assert_redirected_to:
assert_block(msg) do if options.is_a?(Symbol) @response.redirected_to options else options.keys.all? do |k| if k :controller then options[k] ActionController::Routing.controller_relative_to(@response.redirected_to[k], @controller.class.controller_path) else options[k] (@response.redirected_to[k].respond_to?(:to_param) ? @response.redirected_to[k].to_param : @response.redirected_to[k] unless @response.redirected_to[k].nil?) end end end
end
The error was being raised in options.keys.all? block. After breakpoint hackery, I found that there was a mismatch between :id => 1 and :id => ‘1’. The Fixnum was being coerced to a string by the to_param method in this line:
else options[k] == (@response.redirected_to[k].respond_to?(:to_param) ? @response.redirected_to[k].to_param : @response.redirected_to[k] unless @response.redirected_to[k].nil?)
So I have added a modified version of assert_redirected_to to my test_helper.rb file that coerces both the redirect and asserted parameters via to_param before comparing them. This made my problem go away. So here’s the newly modified method:
def assert_redirected_to(options = {}, message=nil) clean_backtrace do assert_response(:redirect, message)
if options.is_a?(String)
msg = build_message(message, "expected a redirect to <?>, found one to <?>", options, @response.redirect_url)
url_regexp = %r{^(\w+://.?(/|$|\?))(.)$}
eurl, epath, url, path = [options, @response.redirect_url].collect do |url|
u, p = (url_regexp =~ url) ? [$1, $3] : nil, url == '/') ? p : '/' + p]
end.flatten
end
end
assert_equal(eurl, url, msg) if eurl && url
assert_equal(epath, path, msg) if epath && path
else
@response_diff = options.diff(@response.redirected_to) if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash)
msg = build_message(message, "response is not a redirection to all of the options supplied (redirection is <?>)#{', difference: <?>' if @response_diff}",
@response.redirected_to || @response.redirect_url, @response_diff)
assert_block(msg) do
if options.is_a?(Symbol)
@response.redirected_to == options
else
options.keys.all? do |k|
value = (options[k].respond_to?(:to_param) ? options[k].to_param : options[k])
if k :controller then value ActionController::Routing.controller_relative_to(@response.redirected_to[k], @controller.class.controller_path)
else value == (@response.redirected_to[k].respond_to?(:to_param) ? @response.redirected_to[k].to_param : @response.redirected_to[k] unless @response.redirected_to[k].nil?)
end
end
end
end
end
Hide comments

RSS
Comments