user483040
user483040

Reputation:

Devise: Why doesn't my logout link work?

the problem: In a nutshell, when I try to install a logout link to my app it fails to work. Here's as much context as I can think to put here (if you want anything else, please poke me)...

I've got this in a haml view:

= link_to("Logout", destroy_user_session_path, :method => :delete)

It generates this in the view:

<a href="/users/sign_out" data-method="delete" rel="nofollow">Logout</a>

I verified that in my config/initializers/devise.rb I have this setting uncommented and correct:

config.sign_out_via = :delete

I validated the following route:

destroy_user_session DELETE /users/sign_out(.:format) {:action=>"destroy", :controller=>"devise/sessions"}

I also have this bit of trickery in my routes.rb, and I suspect this is related to my issue:

devise_for :users, :controllers => {:sessions => "devise/sessions", :registrations => "users"}
resources :users

This last bit is because I want to manage (edit, create and delete) users in my own controller.

The error message I'm getting is as follows:

ActiveRecord::RecordNotFound in UsersController#show

Couldn't find User with ID=sign_out
Rails.root: /home/jaydel/projects/mbsquared-projects/Wilson-Goldrick

app/controllers/users_controller.rb:16:in `show'

In my server logs I see this for the request:

Started GET "/users/sign_out" for 127.0.0.1 at 2011-08-04 13:08:51 -0500
  Processing by UsersController#show as HTML
  Parameters: {"id"=>"sign_out"}

Anyone have any ideas?

Upvotes: 51

Views: 47597

Answers (19)

timjini
timjini

Reputation: 157

I've tried all the solutions mentioned here but the true solution to this issue is the following :

<%= link_to "Sign Out", destroy_user_session_path, 'data-turbo-method': :delete%>

It works if it doesn't just refresh or restart the server.

Upvotes: 11

prashantsahni
prashantsahni

Reputation: 2197

Stop the server
yarn add  "@rails/ujs"
yarn add turbolinks
yarn add @rails/activestorage
My application.js
import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

Rails.start()
Turbolinks.start()
ActiveStorage.start()
Start the server

Upvotes: 0

Gurudath BN
Gurudath BN

Reputation: 1411

1) I feel u may need to install below gem, the request with method: :delete will work else it may go as get

https://github.com/rails/jquery-rails

2) Add this two below lines in application.js

//= require jquery
//= require jquery_ujs

Upvotes: 0

wsizoo
wsizoo

Reputation: 108

As mentioned by Tombart above, the answer for me was putting back the rails-ujs call in my application.js file.

//= require rails-ujs
//= require turbolinks

I had initially removed them to stop errors from having my scripts in the footer be re-evaluated. My workaround was to create a footer.js compile file with the resources I wanted in the footer.

//= require jquery-3.2.1.min
//= require jquery-ui-1.12.1.min
//= require materialize
//= require init

Then in my /initializers/assets.rb file adding a precompile

Rails.application.config.assets.precompile += %w( footer.js )

Then you can call the following in your layout/application.html.erb file.

<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'footer' %>

I keep the application line in my header, and added my new "footer" call before the end of my body tag.

Upvotes: 0

JorgePinon
JorgePinon

Reputation: 355

Since the OP mentioned devise and this problem also happened to me, I just wanted to chime in. @Ross Allen had the correct answer when you don't want to use jQuery_ujs. Rails provides a couple of helpers to solve this without jQuery.

This is Ross's answer but using Devise's current_user model:

<%= form_for(current_user,
    url: destroy_user_session_path, html: { method: :delete }) do |f| %>
    <%= f.submit "Log out" %>
<% end %>

Or the more succinct button_to helper that creates a similar form:

<%= button_to "Log out", destroy_user_session_path, method: :delete %>

Upvotes: 4

askrynnikov
askrynnikov

Reputation: 771

the reason may be in the wrong order connection bootstrap-sprockets

the correct order:

// app/assets/javascripts/application.js

...

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require_tree .

Upvotes: 0

EARnagram
EARnagram

Reputation: 51

If you're finding this problem in production and you're using the asset pipeline, you often need to:

rake assets:clobber in order to clear out your public assets. Then rake assets:precompile before committing and pushing your code (unless your push also precompiles, aka Heroku).

Upvotes: 0

webgen
webgen

Reputation: 183

You need both
link_to "Log out", destroy_user_session_path, method: :delete

&& these included in application.js

//= require jquery
//= require jquery_ujs

. Obviously, don't forget to add this to Gemfile if for some reason it is not there.

gem 'jquery-rails'

Upvotes: 7

Leonard Kakande
Leonard Kakande

Reputation: 695

If your are also having more than one jquery sources in your rails app you need to use the default one specified in the Gemfile

make sure in your Gemfile you have this

gem 'jquery-rails'

and in your assets you do not have any other JQuery source files.

in my case I had a second JQuery file other than the default as declared in the Gemfile so it caused conflicts.

if you previously had those source, be sure to precompile assets again if you had previously done so

Upvotes: 1

errata
errata

Reputation: 26952

I agree that it's more restful to use the http DELETE method, I like to create a simple endpoint to destroy a user session with a GET method.

by adding this to config/routes.rb

devise_scope :user do
  get '/logout',  :to => 'sessions#destroy'
end

Upvotes: 2

RafeekPro
RafeekPro

Reputation: 31

I've checked all this solutions, but no one has worked for me. Finally I found that in header I deleted two lines including application tags and csrf meta

So, If someone have this problem with no sollution at this point - check if you have in header of the page (HAML notation)

= javascript_include_tag 'application'
= csrf_meta_tags 

Upvotes: 2

Ross Allen
Ross Allen

Reputation: 44900

This is an old question, but I wanted a way that required no JavaScript. Rails enables "DELETE" like requests with a hidden input that sets method to delete. Use a real <form>, and let Rails generate the necessary hidden inputs:

<%= form_for(resource, as: resource_name,
    url: destroy_user_session_path, html: { method: :delete }) do |f| %>
  <%= f.submit "Log out" %>
<% end %>

the above generates something like:

<form accept-charset="UTF-8" action="/users/sign_out" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="✓">
    <input name="_method" type="hidden" value="delete">
    <input name="authenticity_token" type="hidden" value="1234">
  </div>
  <input name="commit" type="submit" value="Log out">
</form>

Upvotes: 2

user212131
user212131

Reputation: 49

You also have to check, is resources :users under devise_for :users and is the link method delete

link_to "Logout", destroy_user_session_path, method: :delete

if both are right, your logout button should work

Upvotes: 2

Christoph
Christoph

Reputation: 41

jQuery is required in order to perform the request with DELETE. Make sure you didn't drop it from your application.js.

Upvotes: 4

Kyle d&#39;Oliveira
Kyle d&#39;Oliveira

Reputation: 6382

The problem lies in the fact that in your logs the signout request is a GET request.

Started GET "/users/sign_out"

But the signout route is a DELETE

destroy_user_session DELETE /users/sign_out(.:format) 

The reason why you are getting the exception is that is it getting confused with one of the routes created by resources :users which would be something like

edit_user GET /users/(:id)(.:format) {:action=>"edit", :controller=>"users"}

Basically 'sign_out' is being mistaken as a id.

I'm not sure why the delete link is not going through as a DELETE request. Though changing

config.sign_out_via = :delete

to be :get might solve the problem.

Upvotes: 19

Jay Beale
Jay Beale

Reputation: 899

The correct way to fix this, REST-wise, would be to change your logout links to use the DELETE method. It's a very easy fix, changing this:

link_to "Log out", destroy_user_session_path

to this:

link_to "Log out", destroy_user_session_path, :method => :delete 

Upvotes: 85

pws5068
pws5068

Reputation: 2194

This is an old question but the accepted answer is not the proper way to solve this issue (although it is a good diagnosis of the problem).

When I ran into this today my routes file appeared as:

  root :to => 'welcome#index' 

  resources :users    
  devise_for :users

As mentioned by Olives the resources statement is simply causing /users/anything to trip up. I simply needed to reverse the ordering of my routes...

 root :to => 'welcome#index' 

  devise_for :users
  resources :users

Upvotes: 4

ScottJShea
ScottJShea

Reputation: 7111

I had to go about this in a different manner as my application.rb had:

<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>

and was still failing. It turns out I needed to set config.serve_static_assets = true in /environment/development, test and production.rb. This link was what helped me figure it out.

Upvotes: 1

ka8725
ka8725

Reputation: 2918

I had the same problem with rails 3.2 when I deleted from application.js this line:

//= require jquery_ujs

So, I think you have to insert this line in your application.js if you haven't it there.

PS. This behavior means that rails adapter for jquery doesn't function. So you should make sure if it is loaded in your html in browser. You should test it in development mode because you will have compressed js in production and it will be very difficult to find something there.

Upvotes: 33

Related Questions