Topic: NoMethodError?

I'm getting a lot of these errors as I try to write some functional tests:

NoMethodError: undefined method `first' for :users:Symbol

I have a users fixture and there is an entry in it called first, but I'm not sure that has anything to do with it.

The error line number given is generally a line with assert_redirected_to.

Any ideas?

Re: NoMethodError?

Can you post the code?

Railscasts - Free Ruby on Rails Screencasts

Re: NoMethodError?

It seems to have something to do with a before_filter which tests to see if the user has admin privileges. I'm going to play around with that some and see if I can minimize the code which creates the scenario. Otherwise I'll have to post a mess of code.

Re: NoMethodError?

Post your functional test code.  Are you happening to be doing this:

fixtures :users
def test_something
  first_user = :users.first
  ...
end

should be
  first_user = users(:first)

Re: NoMethodError?

Most of this is code from the scaffold. I changed it a little as I have a before_filter which requires a user to be an admin before they can destroy a user.

  def test_destroy
    assert_nothing_raised {
      User.find(@first_id)
    }

    # only an admin can destroy
    post :destroy, :id => @first_id, :user_id => users(:admin_user).id
    assert_response :redirect
    assert_redirected_to :action => 'list'

    assert_raise(ActiveRecord::RecordNotFound) {
      User.find(@first_id)
    }
  end

Re: NoMethodError?

The functional test you posted looks good to me.  Does that one fail on assert_redirected_to ?

You said it happens on multiple tests.  When it happens on the assert_redirected_to line are you also sending something like :id => users(:first) as a option?

Re: NoMethodError?

OK, I made the destroy test happy by changing the post line a little:

# from
post :destroy, :id => @first_id, :user_id => users(:admin_user).id

#to
post :destroy, { :id => @first_id }, { :user_id => users(:admin_user).id }


But the problem still crops up on the list method, which I only want to allow for admins. So I'll try to include the relevant code.

# from application.rb
  def must_be_admin
    temp_user = User.find(session[:user_id], :select => :level) rescue nil
    if temp_user
      if temp_user.level != "admin"
        logger.debug('must_be_admin - user exists but not admin')
        flash[:notice] = "Access not permitted"
        redirect_to(:controller => :statics, :action => :index)
      end
    else
      session[:original_uri] = request.request_uri
      flash[:notice] = "Please log in"
      redirect_to(:controller => :users, :action => :login)
    end
  end

# from users_controller.rb
  before_filter :must_be_admin, :only => [ :list, :destroy ]

  def list
    @user_pages, @users = paginate :users, :per_page => 20
  end

# from users_controller_test.rb
  def test_list_for_admin_user
    get :list, {}, { :user_id => users(:admin_user).id }

    assert_response :success
    assert_template 'list'

    assert_not_nil assigns(:users) # from scaffold code: not sure what this does
  end

  def test_list_for_non_admin_user
    get :list, {}, { :user_id => users(:normal_user).id }

    assert_response :redirect
    assert_redirected_to :controller => 'statics', :action => 'index'
    assert_template 'statics/show'
    assert_equal 'Access not permitted', flash[:notice]
  end

  def test_list_for_not_logged_in
    get :list, {}, { :user_id => nil }

    assert_response :redirect
    assert_redirected_to :action => 'login'
    assert_template 'login'
    assert_equal 'Please log in', flash[:notice]
  end


test_list_for_admin_user runs OK. The other two tests cause these errors:

  4) Error:
test_list_for_non_admin_user(UsersControllerTest):
NoMethodError: undefined method `first' for :statics:Symbol
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/response_assertions.rb:72:in `assert_redirected_to'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/response_assertions.rb:43:in `each'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/response_assertions.rb:43:in `assert_redirected_to'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions.rb:60:in `clean_backtrace'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/response_assertions.rb:35:in `assert_redirected_to'
    test/functional/users_controller_test.rb:40:in `test_list_for_non_admin_user'

  5) Error:
test_list_for_not_logged_in(UsersControllerTest):
NoMethodError: undefined method `first' for :users:Symbol
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/response_assertions.rb:72:in `assert_redirected_to'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/response_assertions.rb:43:in `each'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/response_assertions.rb:43:in `assert_redirected_to'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions.rb:60:in `clean_backtrace'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/response_assertions.rb:35:in `assert_redirected_to'
    test/functional/users_controller_test.rb:49:in `test_list_for_not_logged_in'

I hope I posted enough code to figure this out. Thanks for having a look.

Re: NoMethodError?

Interestingly, if I change my redirects in application.rb, the NoMethodError goes away:

redirect_to(:controller => :users, :action => :login) # original
redirect_to(:controller => 'users', :action => 'login') # new

I have no idea why that makes a difference, but perhaps the functional test doesn't know what those symbols mean. I wonder if there's some sort of require statement I could add that would fix that?

Now I get another failure from my assert_template lines:
expecting <"login"> but rendering with <nil>

Last edited by boone (2007-09-08 21:20:56)

Re: NoMethodError?

OK, the symbol vs. string problem appears to be a bug:
http://dev.rubyonrails.org/ticket/7535

Would be nice if they fixed it as I like using symbols where I can.

The nil on the redirected template seems to be because the functional test doesn't follow the redirects...that gets done in integration tests apparently.

So I think I'm back on track. Thanks for letting me hash this out here.

Re: NoMethodError?

Thank you so much for posting this!  I was tearing my hair out over the exact same issue; this line in my controller:

redirect_to(:controller => :profiles, :action => 'list')

caused this error in my functional tests:

>> NoMethodError: undefined method `first' for :profiles:Symbol

Changing the controller name from a symbol to a string in the redirect_to fixed it:

redirect_to(:controller => 'profiles', :action => 'list')

I don't know how long it would have taken me to hunt this down if I hadn't found your post!