UsersController DELETE 'destroy' as a non-signed-in user should deny access

  • Question
  • Updated 3 years ago
  • Answered
Right before concluding chapter 10, at listing 10.41 to be exact, where it says that all the tests should pass, I get the following error:

...................................................F.......................................

Finished in 2.66 seconds
92 examples, 1 failure

1) UsersController DELETE 'destroy' as a non-signed-in user should deny access
Failure/Error: delete :destroy, :id => @user
undefined method `admin?' for nil:NilClass

My users_controller.rb looks like this:

class UsersController < ApplicationController
before_filter :authenticate, :only => [:index, :edit, :update]
before_filter :correct_user, :only => [:edit, :update]
before_filter :admin_user, :only => :destroy

def index
@title = "All users"
@users = User.paginate(:page => params[:page])
end

def show
@user = User.find(params[:id])
@title = @user.name
end

def new
@user = User.new
@title = "Sign up"
end

def create
@user = User.new(params[:user])
if @user.save
sign_in @user
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
#@user.password = ""
#@user.password_confirmation = ""
@title = "Sign up"
render 'new'
end
end

def edit
@title = "Edit user"
end

def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
flash[:success] = "Profile updated."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end

def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_path
end

private

def authenticate
deny_access unless signed_in?
end

def correct_user
@user = User.find(params[:id])
redirect_to(root_path) unless current_user?(@user)
end

def admin_user
redirect_to(root_path) unless current_user.admin?
end
end

Help please!!

Edit: 1 - I realized that I was running rspec 2.0.0.beta.18, so I changed it to 2.0.1 like the last Gemfile for Chapter 10, and re-ran the tests.

These are the results I got:

Failures:
1) UsersController DELETE 'destroy' as a non-signed-in user should deny access
Failure/Error: delete :destroy, :id => @user
undefined method `admin?' for nil:NilClass
# ./app/controllers/users_controller.rb:68:in `admin_user'
# ./spec/controllers/users_controller_spec.rb:306:in `block (4 levels) in '

Finished in 2.91 seconds
92 examples, 1 failure

Edit 2: Btw, I ran the code and it works fine. It's just the test is giving me a problem. i.e. I can login as admin and delete users with no issue.
Photo of marcamillionM

marcamillion

  • 13 Posts
  • 0 Reply Likes
  • confused

Posted 5 years ago

  • 1
Photo of Rails Tutorial

Rails Tutorial, Official Rep

  • 1009 Posts
  • 112 Reply Likes
There's an error in your Users controller. See if you can find the problem based on the knowledge that the admin? method is being called on a nil object. What might cause that? Where is admin? being called on anything in the Users controller?
Photo of marcamillionM

marcamillion

  • 13 Posts
  • 0 Reply Likes
In the private section, I have the following:

def admin_user
redirect_to(root_path) unless current_user.admin?
end
Photo of Rails Tutorial

Rails Tutorial, Official Rep

  • 1009 Posts
  • 112 Reply Likes
That's right. Now, why is current_user nil?
Photo of marcamillionM

marcamillion

  • 13 Posts
  • 0 Reply Likes
No idea. Where else can I check?
Photo of Rails Tutorial

Rails Tutorial, Official Rep

  • 1009 Posts
  • 112 Reply Likes
There is a difference between your Users controller and the one in the book. When you find the difference, you will find the bug.
Photo of marcamillionM

marcamillion

  • 13 Posts
  • 0 Reply Likes
There doesn't happen to be a 'final version' of the Users controller anywhere, right? Like there was for the Gemfile at the end of chapter 10.

I would think that the Users controller would be different, because of different implementations done by each individual user - from the exercises at the end of each chapter, right? Or is there only one right way to achieve the desired results from the exercises, and I have done something wrong?
Photo of Rails Tutorial

Rails Tutorial, Official Rep

  • 1009 Posts
  • 112 Reply Likes
There's probably a final version somewhere, but it's not relevant in the present case. The controller you pasted in differs from ListingĀ 10.41 in a small but important way. When you find that difference, you will find the problem.
Photo of marcamillionM

marcamillion

  • 13 Posts
  • 0 Reply Likes
Wow....it was the :destory action for the authenticate before_filter.

That's ridiculous.

All this time I was focussing on the 'nil object', when I should have been focusing on the destory action.

Thanks!
Photo of Rails Tutorial

Rails Tutorial, Official Rep

  • 1009 Posts
  • 112 Reply Likes
You got it! Why was current_user nil? Because the user was not logged in. Then why was current_user.admin? even being called? Because the authenticate before filter wasn't being invoked. That's the chain of logic that leads you backward through the code, terminating at the answer: destroy hadn't been added to the authenticate before filter's list of actions.

The next step in your Rails debugging journey is to be able to work through these kinds issues without my guidance. To that end: the next time you run into trouble, you're on your own. :-)
Photo of Mark Cheshire

Mark Cheshire

  • 2 Posts
  • 0 Reply Likes
I actually learned more from debugging this and finding this explanation, than if the tutorial had be rewritten to make it clear that :destroy had to be added to authenticate before. It really helps to get this experience because it takes practice to get understand how to interpret Ruby error statements. I just hope people reading the dead tree version, can find this help just as easily.
Photo of LanceML

LanceM

  • 1 Post
  • 0 Reply Likes
I second Mark's sentiment. I spent over an hour trying to debug this, spending time on stack overflow and this site, until i stumbled upon this thread. I'm almost certain I learned more this way than "if the tutorial had be rewritten to make it clear that :destroy had to be added to authenticate before." :)
Photo of marcamillionM

marcamillion

  • 13 Posts
  • 0 Reply Likes
Lol.

Thanks for the help.

I know I should be able to debug it properly, but learning ruby, rails, and rspec in and of itself is a bit challenging.

Speaking of which, where can I get a quick tutorial/run down of the RSpec syntax? I picked up some of it, in the rails tutorial, but there were a few stuff that went over my head and I want to get a better understanding of the way RSpec works and how to do TDD.

Also, just a thought for possible improvements to the tutorial, perhaps what you can do explain a bit more (before jumping into the code) what exactly you will be doing and how it ties into everything. You did this well in many sections (e.g. the first few chapters), but I felt like as we got into more of the meat in the last few chapters, you kinda skimped on those types of details.

At one point, I think it was chapter 8 or 9, I got into a mode where I was doing what you said and not really understanding what I was doing.

If you wanted me to give more specific feedback, as in where it was that I shifted into that mode, I could go back through and let you know.

Thanks though.
Photo of Sapphire

Sapphire

  • 5 Posts
  • 0 Reply Likes
I agree with your comments as I had the same issue - the "destroy" action hadn't been added to the authenticate before filter's list of actions.
The reason why we forgot to add the destroy to authenticate in Listing 10.41 was we were focused on adding "A before filter restricting the destroy action to admins" as told by the tutorial, but did not notice destroy action should also be added to the authenticate before filter.
Photo of cantbecoolC

cantbecool

  • 5 Posts
  • 1 Reply Like
I agree with the comments above. I would have liked more explanation for some of the code examples, rather than simply writing it and figuring out what its use is later. Although, the digging through the code trying to determine what a particular line of code does add to the learning process.
Photo of rickschmoo

rickschmoo

  • 2 Posts
  • 0 Reply Likes
I had exactly this same issue. I loved the gentle hunts towards debugging ... I was getting lazy at following the source code. Thanks for keeping us focused
Photo of Yuri Urban

Yuri Urban

  • 1 Post
  • 0 Reply Likes
well, I have slightly different 2 failures:

1) UsersController DELETE 'destroy as an admin user should destroy the user
Failure/Error: lambda do
count should have been changed by -1, but was changed by 0
# ./spec/controllers/users_controller_spec.rb:318:in `block (4 levels) in '

2) UsersController DELETE 'destroy as an admin user should redirect to the users page
Failure/Error: flash[:success].should =~ /destroyed/i
expected: /destroyed/i
got: nil (using =~)
# ./spec/controllers/users_controller_spec.rb:324:in `block (4 levels) in '

Finished in 6.74 seconds
98 examples, 2 failures

----

my tests are:

describe "as an admin user" do

before(:each) do
admin = Factory(:user, :email => "admin@example.com", :admin => true)
end

it "should destroy the user" do
lambda do
delete :destroy, :id => @user
end.should change(User, :count).by(-1)
end
it "should redirect to the users page" do
delete :destroy, :id => @user
flash[:success].should =~ /destroyed/i
response.should redirect_to(users_path)
end

end

my users controller is:

before_filter :authenticate, :only => [:index, :edit, :update, :destroy]
before_filter :correct_user, :only => [:edit, :update]
before_filter :admin_user, :only => :destroy

def destroy
User.find(params[:id]).destroy
redirect_to users_path, :flash => { :success => "User destroyed." }
end

def admin_user
redirect_to(root_path) unless current_user.admin?
end

-----

ANY IDEAS PLEASE? I couldn't find the answer on the Stackoverflow or anywhere else :(