Error: Redirecting in a way that never completes

I am trying to use the session hash to restrict access to a portion of
a web site. I have 2 controllers. The first is ‘main’ for general
access and the second is ‘protected’ for restricted access. I have
appended my ‘protected’ controller to the end of this message. The
operation is real simple. There are only 2 users. If the user is
logged in as ‘user’, he’s supposed to get re-directed to the roster
page. If the user is logged in as ‘admin’, he’s supposed to get re-
directed to the admin page. Otherwise, the user is re-directed to the
login action which is under the main controller.

The problem that I’m having is that when the user is properly logged
in as either ‘user’ or ‘admin’, instead of being re-directed to the
appropriate page I get an error message from FireFox saying, “Firefox
has detected that the server is redirecting the request for this
address in a way that will never complete.” The URL bar of the
browser shows that the browser is trying to display the proper page.
If I try the same thing with IE, the redirected page just never gets
displayed. The Firefox error message goes on to explain that the
problem can sometimes be caused by disabling or refusing to accept
cookies. That’s not the case here.

I really haven’t got a clue as to why this re-direction doesn’t work.
Does anyone know what the problem is; and, more importantly, how to
fix it?

Thanks for any input.

  ... doug

------------- Protected Controller ----------------
class ProtectedController < ApplicationController

before_filter :accessControl

def roster
end

def logout
end

def accessControl
case session[:rank]
when “admin”
redirect_to :controller=>‘protected’,:action=>‘admin’
when “user”
redirect_to :controller=>‘protected’,:action=>‘roster’
else
redirect_to :controller=>‘main’,:action=>‘login’
end
return false
end
end

The problem is that redirect_to does not return so your method is always
returning false even though it is setting the redirect header. Try this
instead:

def accessControl
case session[:rank]
when “admin”
redirect_to :controller=>‘protected’,:action=>‘admin’ && return
when “user”
redirect_to :controller=>‘protected’,:action=>‘roster’ && return
else
redirect_to :controller=>‘main’,:action=>‘login’ && return
end
return false
end

Sorry, I should have paid more attention…seems to be a theme today.
You need to parenthesize the arguments to redirect_to so it’s not
ambiguous. It also appears that anding return true throws an error. I
typically just do && return, but I am not sure if the nil return value
will solve your issue. So try:

redirect_to(:controller=>‘protected’,:action=>‘admin’) && return

If that doesn’t work, tru

when ‘admin’
redirect_to(:controller=>‘protected’,:action=>‘admin’)
return true
when …

Sorry for the problems. I typically test my answers in irb, but
sometimes I get lazy :slight_smile:

Not to beat a dead horse, but this version is better yet as it will
redirect “user” to the appropriate action if they try the wrong action:

def accessControl
case session[:rank]
when “admin”
return true
when “user”
return true if params[:controller] == ‘protected’ &&
params[:action] == ‘roster’
redirect_to :controller => ‘protected’, :action => ‘roster’
else
redirect_to :controller=>‘main’,:action=>‘login’
end
return false
end

You know, I really should have thought of this earlier. I must really be
asleep. Here is the problem. You are using that authenticate method as a
before filter in your controller, but you are always redirecting or
returning false! So what you need to do is this:

class ProtectedController < ApplicationController

before_filter :accessControl

def roster
end

def logout
end

###########
protected
###########

def accessControl
case session[:rank]
when “admin”
return true
when “user”
return true if params[:controller] == ‘protected’ &&
params[:action] == ‘roster’
else
redirect_to :controller=>‘main’,:action=>‘login’
return true
end
return false
end
end

Note that I didn’t test this for typo’s but this should get you going.
In a filter, you must return true to continue with the current request.
If you are always sending a redirect, they will never get there.

I just noticed that you are using this method as a before filter. This
really makes sense now as returning false would stop the chain, but
since the redirect header is set, the browser would get redirected,
then the before filter would get hit again, stop the chain, but
redirect, and on and on and on.

One other thing, you should make the accessControl method protected so
that it can’t be called directly because posting to it and setting rank
manually would bypass access control, so this should be the final
method:

###########
protected
###########

def accessControl
case session[:rank]
when “admin”
redirect_to :controller=>‘protected’,:action=>‘admin’ && return
true
when “user”
redirect_to :controller=>‘protected’,:action=>‘roster’ && return
true
else
redirect_to :controller=>‘main’,:action=>‘login’ && return true
end
return false
end

You need to parenthesize the arguments to redirect_to so it’s not
ambiguous.

You know, I thought about that and actually tried adding the
parenthesis. It didn’t help. The reason I didn’t mention it was that
I looked it up in the ‘Method Arguments’ section of ‘Programming Ruby
– The Pragmatic Programmer’s Guide’. Those guys are pretty darn
thorough. However, they make no mention of there being situations
where parenthesis must be added to clarify what might otherwise be an
ambiguity. So, I just concluded that Ruby must be even smarter than I
thought. Anyway, as I say, it didn’t work. I get the same syntax
error problem. I might add that this parenthesis-not-required-with-
methods thing is one of the bigger hurdles that I’m trying to get over
in adjusting to Ruby. I’m still frequently finding myself saying,
“Oh, that’s a method!”

As far as putting the “return true” on a succeeding line goes, that
takes me back to our old redirecting-in-a-way-that-never-completes
Firefox error. So, I guess that I still don’t have a workable
solution for this. Thanks for the input though.

  ... doug

actually, since it seems you are checking the return value, you should
do:

def accessControl
case session[:rank]
when “admin”
redirect_to :controller=>‘protected’,:action=>‘admin’ && return
true
when “user”
redirect_to :controller=>‘protected’,:action=>‘roster’ && return
true
else
redirect_to :controller=>‘main’,:action=>‘login’ && return true
end
return false
end

Actually, this is better (remove return true from the else so that it
will return false and redirect to the login screen) :

def accessControl
case session[:rank]
when “admin”
return true
when “user”
return true if params[:controller] == ‘protected’ &&
params[:action] == ‘roster’
else
redirect_to :controller=>‘main’,:action=>‘login’
end
return false
end

Thanks for the input, Bill. What you say makes perfect sense and it
would seem that your solution would just work out of the box.
However, what actually happens is that I get a syntax error:

/var/www/rails/app/controllers/protected_controller.rb:15: syntax
error
redirect_to :controller=>‘protected’,:action=>‘admin’ &&
return true

^
/var/www/rails/app/controllers/protected_controller.rb:17: syntax
error
redirect_to :controller=>‘protected’,:action=>‘roster’ &&
return true

^
/var/www/rails/app/controllers/protected_controller.rb:19: syntax
error
redirect_to :controller=>‘main’,:action=>‘login’ && return
true

^
Although it doesn’t look that way in what I pasted into this message,
the ‘^’ actually marks the end of the line. I sure don’t see anything
wrong with your syntax. In any event, hopefully I’m headed in the
right direction now. I just need to figure out what the problem is
with that syntax. Thanks.

     ... doug

Just FYI, I finally got this thing to work. Thanks to the list and
especially to Bill for all of the superb help. I’m appending the code
for my working ‘protected’ controller. Turns out to be pretty simple,
huh? Thanks again.

class ProtectedController < ApplicationController

before_filter :accessControl

def roster
end

def admin
end

def logout
end

#############
protected
#############

def accessControl
if session[:rank]!=‘admin’ && session[:rank]!=‘user’
redirect_to :controller=>‘main’,:action=>‘login’
return
end
end

end