5

I only get this error when I manually enter the URL into the browser. If i click the "sign out" link on my site, it logs the user out fine. This is my "sign out" link:

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

which works perfect. How can I get the sign out functionality working if the user types the address into the address bar? I know it has to do with GET and DELETE requests. It is using a DELETE request with the link, but using a GET request when the URL is manually entered. How can I fix this?

theDazzler
  • 1,039
  • 2
  • 11
  • 27
  • 1
    In RESTful architecture, the DELETE request means that we are actually requesting to delete some resource from the server. And while logging out from the application, we are actually requesting to destroy/delete the session from the server. Hence following the RESTful architecture, we must not let the user to sign out by typing in the URL. It is a bad practice. – Manoj Monga Jan 10 '14 at 12:04
  • So what do most rails apps do that use devise to prevent the user from typing in the url and displaying the error page? – theDazzler Jan 11 '14 at 01:50
  • We don't need to define anything. If the method is not matching the route rails itself will en-route to 404 status. – Manoj Monga Jan 13 '14 at 06:21

8 Answers8

10

Adding;

devise_scope :user do get '/users/sign_out' => 'devise/sessions#destroy' end

to the Routes fixed my issue.

Quaso
  • 373
  • 1
  • 6
  • 18
7

Modify devise.rb to

config.sign_out_via = :get

And change the link

<%= link_to "log out", destroy_user_session_path, method: :get %>
Kick Buttowski
  • 6,709
  • 13
  • 37
  • 58
lalameat
  • 754
  • 3
  • 10
  • 5
    I don't want to do that. I know that is a solution, but it isn't the best practice. I want to keep using DELETE – theDazzler Jan 10 '14 at 09:26
7

Basically, When you try to type url manually or you try to clickin link "sign-out" with new tab there are HTTP GET request and you will get No route matches [GET] "/users/sign_out", it doesn't exist because you have only via DELETE request for /users/sign_out on your routes.rb , for the solution you can add this in config/initializer/devise.rb

# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = Rails.env.test? ? :get : :delete

And change DELETE to MATCH request on your routes.rb

e.g : match 'users/sign_out' => "devise/sessions#destroy"

For reference : Devise for user management and authentication.

To be honest, supposed change the default 'delete' HTTP method it is not recommended. It's to user for test (e.g using cucumber) Cucumber Testing for “Sign Out”

Jose Valim explained why: “GET requests should not change the state of the server. When sign out is a GET request, CSRF can be used to sign you out automatically and things that preload links can eventually sign you out by mistake as well.”

@manoj mona's say 'we must not let the user to sign out by typing in the URL. It is a bad practice'

So, If user to sign out by type in the URL.

  1. You can to define it, if get request it will redirect or render notice (like stackoverflow sign out)

  2. Or don't use link_to tag for sign out, use input tag with form (like facebook sign out), so users can't type in the URL see this answer

Community
  • 1
  • 1
rails_id
  • 8,120
  • 4
  • 46
  • 84
  • 3
    so does everyone that uses devise have to do this to get it to work correctly? It seems like this problem shouldn't exist as the default – theDazzler May 17 '14 at 19:40
  • So, you want devise to change the default HTTP method ? It's not problem but the problem in your `if users sign out typing in the URL`. too many ways to prevent users typing in the url, see this site, facebook site, twitter site etc. I've updated my answer. – rails_id May 18 '14 at 05:02
4

Add this to application.js:

//= require jquery_ujs 
Undo
  • 25,519
  • 37
  • 106
  • 129
vimesh
  • 41
  • 1
2

I have no idea what is the reason (i'm new to ruby on rails), but once you add this line to you applicaiton layout your problem will be solved,

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

and keep the logout link as follows

<%= link_to "Sign Out", destroy_user_session_path, :method => :delete %>
Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
  • This helped me fix it. In my case I had `<%= javascript_include_tag "default", "data-turbolinks-track" => true %>` but when I changed it to `<%= javascript_include_tag "application", "data-turbolinks-track" => true %>` it worked. Although my syntax for the sign out link is slightly different so try change the `:method => :delete` to `method: :delete` if the above solution still doesn't work. – mikeym Mar 28 '16 at 22:51
  • @mikeym `method: :delete` is a shorthand for `:method => :delete` – Hossam Khamis Oct 11 '16 at 20:46
1

Try this

In Routes

devise_scope :user do
  get '/users/sign_out' => 'sessions#destroy'
end
Bachan Smruty
  • 5,686
  • 1
  • 18
  • 23
1
devise_scope :user do
  match '/users/sign_out' => 'sessions#destroy', via: [:get, :delete]
end
junil
  • 758
  • 5
  • 12
0

I added ActiveAdmin::Devise.config to my routes.rb. So the full line is,

devise_for :users, ActiveAdmin::Devise.config

It's actually in the gem's generator so I believe it's supposed to be in there but I've noticed it doesn't get added in some of my installs.

haley
  • 1,573
  • 2
  • 12
  • 19