Forum: Ruby on Rails Sudden failure of redirect in ActionController +verify+

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
06fa952559609d00a12ad22d74335282?d=identicon&s=25 Fritz Anderson (fritza)
on 2008-10-28 17:19
= 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
06fa952559609d00a12ad22d74335282?d=identicon&s=25 Fritz Anderson (fritza)
on 2008-10-28 19:11
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 topic is locked and can not be replied to.