Devise destroy session doesn't destroy the session? - ruby-on-rails

Really new to devise - it's very frustrating in all honesty...
My user session isn't being destroyed.
Here is the link in my navbar:
<li><%= link_to 'Logout', destroy_user_session_path, :method => :delete %></li>
devise.rb has the :delete method configured:
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :delete
Route is:
destroy_user_session DELETE /users/sign_out(.:format) sessions#destroy
Application controller says :
class ApplicationController < ActionController::Base
protect_from_forgery
private
def after_sign_out_path_for(resource_or_scope)
root_path
end
I click my sign out link and my console shows :
Started GET "/users/sign_out" for 127.0.0.1 at 2014-04-18 12:00:26 -0500
Processing by UsersController#show as HTML
Parameters: {"id"=>"sign_out"}
MONGODB (0.8ms) waittext_development['users'].find({:_id=>BSON::ObjectId('53515685963e6507ad00003e')}).limit(-1)
It doesn't seem to be finding an active session (I've clicked it a dozen times in frustration), but the problem is the page I land out - UsersController#show - is not the page I've told it to route to. It should be the root_path which is users#index
So I was getting all these nil class errors on users#show because it was trying to render the default rails #user.name, etc. and #user isn't defined - I finally manually overrode the show action to simply render 'index' and I end up on my index page - BUT STILL - I'm seeing current_user.email printed here:
<% if user_signed_in? -%>
<ul>
<li><%= current_user.email %></li>
<li><%= link_to 'My info', edit_user_registration_path %></li>
<li><%= link_to 'Sign out', destroy_user_session_path %></li>
</ul>
It is evaluating TRUE and I'm getting those three list items.
User should not be signed in because I just destroyed the session!
What the heck?

You issue a GET request, not a DELETE (or even a POST with a set _method parameter to emulate a proper DELETE). As such, your request is routed to UsersController#show which listens to GET /users/:id.
The reason for that is, that a plain HTML link normally can only lead to GET requests. For anything else, you need a form. If you now pass the :method parameter to the link_to method in your view, Rails will generate some Javascript which captures the click on the link to generate a form and send the request that way. This will fail if the user has Javascript disabled, which seems to be the case here.
You should thus either ensure that all users (including you) have Javascript enabled or use something like button_to instead which will create a proper form in HTML which works without Javascript.

This is how i have implemented this so known to work:
devise_scope :user do
match "sign_out", :to => "sessions#destroy", via: [:delete]
end
<%= link_to sign_out_path, :method => "DELETE" do %>
<% end%>

Related

Why do I get Rails 7 Routing Error although route is defined?

I'm following the Rails Tutorial by Michael Hartl to build a tiny demo app. I'm stuck at the logout. This is my routes.rb:
Rails.application.routes.draw do
resources :users
get "/login", to: "sessions#new"
post "/login", to: "sessions#create"
delete "/logout", to: "sessions#destroy"
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
root 'users#index'
end
This is the relevant controller action:
def destroy
log_out
redirect_to root_url, status: :see_other
end
This is the session helper defining log_out:
def log_out
reset_session
#current_user = nil
end
and this is the link tag in the view:
<%= link_to "Log out", logout_path, data: { 'turbo-method': :delete } %></span>
Screenshot of error
When I click on the logout link, I get this error. Expected behaviour: Log user out, redirect to login screen.
What am I doing wrong?
I don't know whether it's because of Turbo, or whether Turbo is even correctly installed. I've added gem 'turbo-rails' to the Gemfile and ran bundle afterwards without any effect.
For me, adding the method: :delete worked along with data-turbo.
<span>
<%= link_to "Log out", destroy_user_session_path,method: :delete, data: { 'turbo-method': :delete } %></span>
You were accessing the DELETE method route via GET. Have you run
rails turbo:install
You may want to change the sign out via GET instead of Delete in config/devise.rb
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :get # <= change this from :delete to :get and remove the `method:` in your `link_to` helper
Here's the references:
https://github.com/hotwired/turbo-rails
https://github.com/heartcombo/devise/issues/5439
Check with passing method
<%= link_to "Log out", logout_path, method: :delete, data: { 'turbo-method': :delete } %>
or
<%= link_to "Log out", logout_path, method: :delete %>
You can change link_to to button_to
<%= button_to "Log out", logout_path, method: :delete %>
It will be less magic but more reliable because not a link but form is used (in normal life, clicking on link is a GET request)

Ruby on Rails Custom Controller Action for Users Controller

Working on versions:
Ruby: 3.0.2
Rails 6.1.4
I'm trying to put a button in my View template for "Users" that will set the :mod attribute to false, with the button just being "Demote User".
I had it working SOMEHOW using a helper method, demote_user, and some variation of
<% if logged_in? && current_user.admin? %>
<%= link_to "Demote User", user_path(#user), onclick: demote_user(#user), class: "btn btn-info" %>
<% end %>
I messed up however it was working when trying to move this method into a controller for best practice. I'm not sure what format worked out, but I've tried many such as
:onclick => demote_user(#user)
onclick: 'demote_user(#user)'
onclick=demote_user(#user)
onclick='demote_user(#user)
and etc. Somehow, it did eventually work but I busted it. Now, every time I load the User's page, it's just executing demote_user(#user) without even needing to click the button, so refreshing a User's page is demoting them.
I am now trying to do this properly by creating a demote method in the UserController, but I have NO IDEA how to make the route, or make it work properly. Up until now, all my routes have been working using resources, and the basic new, create, destroy, etc.
I've been trying many different routes, and view formatting, with no luck and usually ending up with just: Routing Error
No route matches [GET] "/demote.3"
I'd like to be able to avoid using the Javascript onClick functionality and do it properly with the controller even if I could remember how to make it work, but I think my route, or view page, or controller is incorrect. Here are the contents of each file:
Controller
def demote
byebug
#user = User.find(params[:id])
#user.mod = false
redirect_to user_path(#user)
end
View
div class="container text-center mt-4">
<% if logged_in? && current_user.admin? %>
<%= link_to "Demote User", demote_path(#user), class: "btn btn-info" %>
<% end %>
</div>
Routes
Rails.application.routes.draw do
root 'pages#home'
get 'about', to: 'pages#about'
resources :articles
get 'signup', to: 'users#new'
resources :users, except: [:new]
get 'login', to: 'sessions#new'
post 'login', to: 'sessions#create'
delete 'logout', to: 'sessions#destroy'
resources :categories
post 'demote', to: 'users#demote'
end
Up until now, I've been following a course, and I've nailed everything in it and have added some of my own functionality, but I'm still not quite sure how to make sense of routes, or what paths it creates.
I'd like to make other similar custom controller functions beyond show, index, create, delete, update which are all I really understand how to build. I'm not even sure if POST is the correct call in the route.
I would just setup an additional RESTful action for the resource:
resources :users do
patch :demote
end
<% if logged_in? && current_user.admin? %>
<%= button_to "Demote User", demote_user_path(#user), method: :patch %>
<% end %>
You can use link_to instead of button_to but you need to use the correct method: :patch or data: { turbo_method: :patch } option depending on your version of Rails to get the javascript driver to do its trickery.

My link and route is not working in rails

My problems started right out of the gates, lol.
Basically, my button linked to a signup form is not going anywhere and just keeps coming back to my home page where I started.
Here is my home page where the sign up button is.
<!DOCTYPE html>
<html>
<head>
<title>Flight Scheduler</title>
</head>
<body>
<nav>
</nav>
<h1>Welcome to the Flight Scheduler</h1>
<%= button_to "Login", '/login', method: :get%>
<%= button_to "Sign Up", '/users/new', method: :get %>
</body>
</html>
Here is my route for it.
root 'static#home'
#users
get '/users/new', to: 'users#new', as: 'new_user'
Lastly here is my controller
class UsersController < ApplicationController
def index
#users = User.all
end
def new
#user = User.new
end
def create
#user = User.create(user_params)
session[:user_id] = #user.id
redirect_to '/welcome'
end
private
def user_params
params.require(:user).permit(:name,:password,:admin)
end
end
When I click the sign-up button it doesn't leave the home page. When modified it earlier, it gives me a error that no route matchs [GET] '/users/new', but when I did my rake routes command it is there. How can I get over this hump?
You can try to replace the helper button_to to link_to.
<%= link_to "Login", '/login' %>
<%= link_to "Sign Up", '/users/new' %>
As said by Vinícius Alonso, you should use link_to instead of button_to. I am guessing that maybe when you click that button you are making an ajax, and RoR is making that request with format .js and with data-remote = true. That means your server are sending a empty body to your front, and instead changing a location are handling that petition by javascript. So, thats why is not changing. With link_to, RoR generates an anchor, and all your troubles will be solved.
If you are using button_to, to making any other behaivor, you just add local= true to button_to helper!
Good luck!

How to manually specify a :delete request in the URL?

Situation:
I want to destroy the current session in Rails, and am currently signed into an admin model setup via devise.
I thought it would be enough to input site.io/admins/sign_out into the URL, but this assumes a GET request and doesn't work.
No route matches [GET] "/admins/sign_out"
A method: :delete request needs to be made to destroy the session.
Can something be done like site.io/admins/sign_out{action:delete}?
UPDATE
Per request, this is the route related to admin.
devise_for :admins
try this:
<%= link_to "Sign Out", destroy_admin_session_path, :method => :delete %>
To log out with devise you need to POST to /admins/sign_out. I use rails link_to to help with this.
<%= link_to "Log Out", destroy_admin_session_path, method: :delete %>
You could also do it without ERB or link_to
<a rel="nofollow" data-method="delete" href="/admins/sign_out">Log Out</a>
For user model, just replace admin with user
<%= link_to "Log Out", destroy_user_session_path, method: :delete %>
or
<a rel="nofollow" data-method="delete" href="/users/sign_out">Log Out</a>
Source: https://github.com/plataformatec/devise/wiki/How-To:-Add-sign_in,-sign_out,-and-sign_up-links-to-your-layout-template
No you can not manually type in the link on the browser and log it out because in the browser you can't specify PUT POST or Delete.If you define the logout path as GET Method you can directly enter the path and log it out as browser by default gives a GET method. you can do it on Rest Client like postman like below
http://localhost:3000/users/sign_out.html
select method as DELETE
If you inject site.io/admins/sign_out forcefully.
It will send you to the show action of the controller with Parameters: {"id"=>"sign_out"}. Because It assumes that, it is a show action rather than calling the Delete function.
So, I think it is not possible, to forcefully use delete method directly from URL.

unable to use sign_out in ruby on rails devise gem

In my small rails app I have a controller called say and two pages hello and goodbye in it. I installed devise in the app. Initially i was able to access the sing_in page as /users/sign_in and similarly for sign up. I was not able to sign out and due to not able to sign out i am not able to access sign up or sign in page again. Now I entered the following code int eh say/hello page
<h1>Say#hello</h1>
<% if user_signed_in? %>
Hey signed in as <%= current_user.email %>.Not you?
<%= link_to "Logout", destroy_user_session_path %>
<% else %>
Hey <%= link_to "Login", new_user_session_path %> or Hey <%= link_to "Logup", new_user_registration_path %>
<% end %>
</p>
This the routes page of the app.
Demo::Application.routes.draw do
devise_for :users
get "say/hello"
get "say/goodbye"
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root :to => "say#hello"
end
Whenever I access the say/hello page, this is the output i get
Links
Hey signed in as x#gmail.com.Not you? Logout
When I click logout. It says
No route matches [GET] "/users/sign_out"
When I directly access users/sign_in I get routed to the say/hello page.
What mistake am I doing? How should I sign_out?
I have also tried
destroy_user_session_path, :method => :delete
Hope this could help
Try this in your routes.rb
devise_for :users do get '/users/sign_out' => 'devise/sessions#destroy' end

Resources