I’m working through the Michael Hartl Tutorial and am having trouble getting sign-outs to work.
Instead of ID’ing by email, I’m working by username.
Signing up and singing in both work fine, but my sign out causes an error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with username = signout
app/controllers/users_controller.rb:9:in `show'
Why is it looking in the users_controller, in the show method? Why is it calling that? It should be calling sessions controller’s delete method, right?
The offending line 9 is:
8 def show
9 @user = User.find_by_username!(params[:username])
10 end
I don’t understand where the parameters are getting passed in (where and to what) that cause it to think “signout” == the username, rather than finding by username and routing to session#destroy. How can I diagnose this? What can I type in the Rails console to find out what is currently contained in params?
Update:
I thought the solution below worked when I tried it immediately, but the problem had just changed from one error message to another. I have moved the routes around as suggested and am still getting
Request Parameters: {"username"=>"signout"} just this time it’s located in my
`Users#show model: users/show.html.erb where line #1 raised:
undefined method username' for nil:NilClass
Extracted source (around line #1):
1: <\h2><%= @user.username %><\/h2>
2:
3: <!--
4:`
And here are the contents of my routes.rb file:
match 'signup', to: 'users#new'
match 'signin', to: 'sessions#new'
match 'signout', to: 'sessions#destroy', via: 'delete'
resources :sessions, only: [:new, :create, :destroy]
match "/:username" => "users#show", via: "get"
resources :users
I’m guessing you have a route which looks like this:
Before this, you probably have a line that looks like this:
The problem is that routing to
/users/signoutwill match/users/:username, and send your request to theshowaction of theUsersController, settingparams[:username]to"signout". You are then callingUser.find_by_username!("signout")You need to put your
/users/signoutroute above your/users/:usernameline so that it is matched before the/users/:usernameroute. Remember that Rails stops trying to find a matching route at the first one which can match a request URI. Your more generic wild-card routes must appear after more specific routes that have the potential to overlap.RE: Your update
Your
signoutroute requires an HTTP DELETE request, which rails simulates via a POST request with a_method=deleteparameter.In order to match this route, you need to use a form or a
button_toto issue a DELETE request:Destroying sessions is (in my opinion) a special case where you should accept any type of HTTP request. Users should be able to type
/logoutor/signoutinto their address bar and destroy their session via a GET request. I strongly suggest your remove thevia: :deleteand use the following:Conversely, you’re being too lenient with your
signupandsigninroutes, which should use GET and POST requests specifically, and route tonewandcreateactions rather than to the same action.Nothing. You cannot inspect the
paramshash via the Rails console, because there is no request. You can inspect in your log files by addinglogger.info(params.inspect), or in the browser by raising it as an error message:raise params.inspect.