Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #5921 (closed defect: worksforme)

Opened 3 years ago

Last modified 2 years ago

assert_redirected_to report invalid redirection for good redirection

Reported by: nico@bounga.org Assigned to: David
Priority: normal Milestone:
Component: ActionPack Version: 1.1.6
Severity: normal Keywords: assert_redirected_to
Cc:

Description

I've got a strange problem. In my test code I'm doing the following :

   def test_index_user_not_login
     get :index
     assert_response :redirect
     assert_redirected_to :controller => "user", :action => "login"
   end

and when I launch the test, I've got this error :

1) Failure:

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: <{}>

The redirect_to I use is using exactly the same parameters than those used in the assertion.

So if I understand, the testing task tells me that my redirection isn't correct (I tested it by hand and it works well) and that the difference is {}, so nothing different ... Odd.

If I change:

assert_redirected_to :controller => "user", :action => "login"

to:

assert_redirected_to @controller.url_for(:controller => 'user', :action => 'login')

it works like a charm ...

Change History

08/28/06 17:34:25 changed by benedikt <benjovi@gmx.net>

  • version changed from 1.1.5 to 1.1.6.

Also applies to 1.1.6

One of the reasons is the usage of ActionController::Routing.controller_relative_to, which does not work well together with absolute (i.e. leading '/') controller paths.

Also, the error message is misleading, because it suggests that the actual redirect has to match the expected redirected exactly. Furthermore, the controller path name used for building the error message is computed using a different approach.

irb
>> ActionController::Routing.controller_relative_to('/signon','/instructor/main')
=> "signon"

A quick fix (for me) was to alter this method:

--- actionpack-1.12.5/lib/action_controller/routing.rb 
+++ actionpack-1.12.5r/lib/action_controller/routing.rb 
@@ -14,7 +14,7 @@
       def controller_relative_to(controller, previous)
         if controller.nil?           then previous
-        elsif controller[0] == ?/    then controller[1..-1]
+        elsif controller[0] == ?/    then controller
         elsif %r{^(.*)/} =~ previous then "#{$1}/#{controller}"
         else controller
         end
       end

benedikt

(follow-up: ↓ 4 ) 08/29/06 22:10:38 changed by benedikt <benjovi@gmx.net>

As the change above will break redirects with absolute pathnames, it is propably better to wait for a proper fix...

(in reply to: ↑ 2 ) 10/20/06 02:24:23 changed by blakewatters

I have found that this bug is also triggered in cases where to_param coersion causes a string to be compared to an integer. In my application, the ID param was failing comparison with :id => 1 being compared to :id => '1' after to_param on the Fixnum was triggered. I have worked around this with the following new assert_redirected_to in my test_helper.rb file:

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]
          [u, (p[0..0] == '/') ? p : '/' + p]
        end.flatten

        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
    end
  end

01/17/07 22:30:52 changed by manfred

  • status changed from new to closed.
  • resolution set to worksforme.

I've tried this with various permutations in redirect_to and assert_redirected_to. I have seen this problem in the past, but I can't reproduce it anymore. I assume it has been fixed.