Sudden failure of redirect in ActionController +verify+

= SUMMARY

An ActionController +verify+ directive redirects to an :action if
certain actions are not done by POST. In one case, the redirect is to an
empty hash instead; in another, nearly identical, it is to the correct
hash. This is seen in a functional test.

Will someone please tell me what is going wrong, and how I can correct
it?

= ENVIRONMENT

$ ruby --version
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]
$ rails --version
Rails 1.2.6

= DETAIL

(Much of this may be easier to see in the “CODE” section, below.)

AdminController is a subclass of ActionController, acting on instances
of Permission, an ActiveRecord subclass. Permission#approve and
Permission#deny set the :approval attribute to one string or another.
admin/approve/:id and admin/deny/:id pass the respective methods to the
id’ed Permission.

AdminController has a +verify+ directive to require that #approve and
#deny be done by POST. If they are not, the session is to :redirect_to
admin/list.

Class AdminControllerTest, a Test::Unit::TestCase, challenges the
+verify+ by using GET requests instead. For many iterations of the test,
AdminController passed. I then added some tests to AdminControllerTest;
I did not change test_deny_not_post or test_accept_not_post.

test_deny_not_post then started failing at assert_redirected_to. The
fail message is:

“response is not a redirection to all of the options supplied
(redirection is <{}>), difference: <{“action”=>:list}>”

test_approve_not_post, which is nearly identical, DOES NOT fail.

Changing the +verify+'s :redirect_to to { :controller => :admin, :action
=> :list } gets the tests past the assert_redirected_to, but fails the
follow_redirect (Can’t follow redirects outside of current controller
(from admin to admin)). This failure is in BOTH test_deny_not_post and
test_approve_not_post.

My controller is failing a functional test, and I don’t understand why.
Will someone please tell me what is going wrong, and how I can correct
it?

= CODE (abridged)

class AdminController < ApplicationController
verify :method => :post, :only => [ :destroy, :create, :update,
:deny, :approve ],
:redirect_to => { :action => :list },
:add_flash => { :notice => ‘You cannot do this directly.’ }

def approve
# before_filter sets @permission
@permission.approve
if @permission.save
flash[:notice] = ‘This request was approved.’
else
flash[:notice] = ‘Could not approve the request (internal
error).’
end
redirect_to :action => :list
end

def deny
# before_filter sets @permission
@permission.deny
if @permission.save
flash[:notice] = ‘This request was denied.’
else
flash[:notice] = ‘Could not deny the request (internal error).’
end
redirect_to :action => :list
end

class AdminControllerTest < Test::Unit::TestCase

#setup puts user credentials in @session

def test_approve_not_post
get :approve, { :id => 3 }, @session
assert_response :redirect
assert_redirected_to :action => :list
assert_equal ‘You cannot do this directly.’, flash[:notice]
end

def test_deny_not_post
get :deny, { :id => 3 }, @session
assert_response :redirect
assert_redirected_to :action => :list
assert_equal ‘You cannot do this directly.’, flash[:notice]
end
end

I’ve narrowed the problem a bit. It now seems that follow_redirect in
one test will break an ActionController’s +verify+ directive in another,
later test.

I am ashamed to say my code fragment was not accurate. Here is the
correct code:

======
class AdminControllerTest < Test::Unit::TestCase
# #setup puts user credentials in @session

def test_approve_not_post
    get :approve, { :id => 3 }, @session
    assert_response :redirect
    assert_redirected_to :action => :list
    assert_equal 'You cannot do this directly.', flash[:notice]

    ### OMITTED IN ORIGINAL - SORRY ###
    follow_redirect
    assert_response :success
end

def test_deny_not_post
    get :deny, { :id => 3 }, @session
    assert_response :redirect
    assert_redirected_to :action => :list
    assert_equal 'You cannot do this directly.', flash[:notice]

    ### OMITTED IN ORIGINAL - SORRY ###
    follow_redirect
    assert_response :success
end

end

Note that I have the tests follow the redirect_to arising from the
failed +verify+.

I have discovered that if I comment-out the follow_redirect and
assert_response calls in test_approve_not_post, then +verify+ will
redirect correctly in test_deny_not_post. Remember it was the
assert_redirected_to, and the redirection hash, that broke.

So now: follow_redirect breaks an ActionController’s +verify+ handling.
before_filter and after_filter don’t have this problem. Is this a
peculiarity of functional tests – and can I therefore ignore it? I’d
rather be able to test the redirection.

Should I update beyond Rails 1.2.6? 2.x is not feasible for my
deployment.

Again, I’m sorry about mischaracterizing the code.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs