Sudden failure of redirect in ActionController +verify+


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?


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


(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         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         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: