Couldn't find User with id=sign_out - ruby-on-rails

Sign-out link isn't working in my rails application.
I have checked my routes.rb which is listed below and my application.html.erb looks to follow the right path.
Getting the following error.
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with id=sign_out
Rails.root: /Users/patrickwalsh/rails_projects/ytutorial
Application Trace | Framework Trace | Full Trace
app/controllers/users_controller.rb:4:in `show'
lib/disable_assets_logger.rb:11:in `call'
My routes.rb
Refectory::Application.routes.draw do
devise_for :users, :controllers => { :registrations => "users" }
devise_scope :user do
get 'login', to: "devise/sessions#new", as: "login"
get 'logout', to: "devise/sessions#destroy", as: "logout"
get 'logout', to: "users/sessions#destroy", as: "logout"
get 'signup', to: "users#new", as: "signup"
match '/users/:id', :to => 'users#show', :as => :user
end
root :to => 'tutorials#index'
devise_for :users do get '/users/sign_out' => 'devise/sessions#destroy'
get 'users/:id' => 'users#show'
end
resources :tutorials
resources :comments, only: [:show, :create, :update, :destroy]
resources :tutorials do
member { post :vote }
end
if Rails.env == "development"
match 'errors/404' => 'errors#error_404'
match 'errors/500' => 'errors#error_500'
end
unless Rails.application.config.consider_all_requests_local
match '*not_found', to: 'errors#error_404'
end
match 'tagged' => 'tutorials#tagged', :as => 'tagged'
end
and my application.html which seems to be following the right route from what I can see.
Any help is greatly appreciated!
<% if current_user.present? %>
<li><%= link_to "Log out", destroy_user_session_path, (:method => "delete") %></li>
<% else %>
<li><%= link_to "Log in", new_user_session_path %></li>
<li><%= link_to "Sign up", new_user_registration_path %></li>
<% end %>
My users controller as well as I have a suspicion this is where the problem lies but not sure what the error is.
class UsersController < Devise::RegistrationsController
def show
#user = User.find(params[:id])
#tutorials = #user.tutorials
end
end

I had the same issue. My routes were in the correct order, the link_to method was properly used, and Rails kept triggering the users/:id route with :id => :sign_out. I figured out that was because I removed jquery_ujs from my application.js file...
jquery_ujs handles the data-method attribute in the links (generated by link_to when you use the method option), which is used to determine the correct route as explained here: https://thoughtbot.com/blog/a-tour-of-rails-jquery-ujs
So just make sure the you have the following included in your application.js:
//= require jquery
//= require jquery_ujs

If you are calling /users/sign_out directly from the URL it won't work because the routes is:
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
id est, it uses the DELETE method. You need to change your devise initializer to:
config.sign_out_via = :get
other option would be to create a small form and its button with DELETE as method.

This worked for me
#form
<%= link_to(destroy_user_session_path, {:class => "nav-link", :method => :delete}) do %>
<span class="sidebar-normal"> Logout </span>
<% end %>
#routes
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
end

I have started noticing this error after removing rails-ujs. This was done as part of the upgrade to Rails 7 with ImportMap and Hotwire suite. Changing link_to to button_to has fixed this error in this case.
<%= button_to 'Log out', destroy_user_session_path, method: :delete %>
https://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#replacements-for-rails-ujs-functionality

None of this solutions worked for me.
Also it happens just in development mode for me...
I fixed it by adding
if params[:id] = "sign_out"
sign_out current_user
return
end
in the set user function. Not the prettiest solution but it works...

You need to move:
devise_for :users do get '/users/sign_out' => 'devise/sessions#destroy'
over your devise_scope. Rails is looking for routes from top of Routes file. Your sign out url matches users/:id, hence it is trying to render show action with sign_out being an id.
UPDATE:
Actually, do you really need the last line in your devise_scope block?

Since non of the other answers worked, I found that you could change the base path for every Devise endpoint as described here. So, what I did was to user devise_for on routes.rb:
devise_for :users,
path: 'devise'
Then, all my Devise routes started with devise instead of users so the conflict was gone.

Sorry to bump this up but the "correct" anwser is not to mess around with routes risking breaking many things.
IF you want a disconnect on a GET then actually configure Devise like so in initializer/devise.rb
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :get
As mentionned in the Devise documentation.

Short answer: use link_to with method DELETE
<%= link_to 'Logout', destroy_user_session_path(current_user), method: :delete %>
explanation:
If you take a look at your Routes you'll see
Helper
destroy_user_session_path
the HTTP verb is
DELETE
the Path
/users/sign_out(.:format)
Controller#Action
devise/sessions#destroy
link_to defaoult method is get, this is "the why" (in a simplistic way of explaning). However, you can specify by using method: :method name

I got this error when using devise in a rails 7 app (with bootstrap):
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=sign_out)
I don't fully understand it myself yet, but basically just open another terminal window, type ./bin/dev and hit enter, and (I guess) it loads your javascripts.

Related

Allow admin to activate or deactivate users-- Rails

I've managed to make an app that works only to sign up and to log in. Currently, I'm allowing users by mail account activation (following this tutorial: https://www.railstutorial.org/book/account_activation_password_reset and by 'rails generate controller AccountActivations --no-test-framework') but I want admin to be able to activate or deactivate users. In my users model, I managed to define two methods:
def activate_account!
update_attribute :is_active, true
end
def deactivate_account!
update_attribute :is_active, false
end
And on my users partial view, I managed to
<% if current_user.admin? && !current_user?(user) %>
<%= button_to "Deactivate", user, data: { confirm: "Are you sure?" } %>
<% end %>
My routes look like this:
get 'password_resets/new'
get 'password_resets/edit'
root 'static_pages#home'
get 'help' = 'static_pages#help'
get 'about' = 'static_pages#about'
get 'contact' = 'static_pages#contact'
get 'signup' = 'users#new'
get 'login' = 'sessions#new'
post 'login' = 'sessions#create'
delete 'logout' = 'sessions#destroy'
resources :users
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
The problem is that I don't know how to proceed. I don't want to use either Devise or CanCan because, as a beginner, I want to know how to do it manually. Please help me in implementing activation and deactivation of users from application (Admin can only this).
Here is my app.
Ok, first read chapters 9 and 10 of Hartl's Rails Tutorial.
Add and admin flag to users
rails g migration add_admin_to_users admin:boolean
This will give you .admin? "for free" as Active Record will generate this method.
And I'd write your button like this
<% if current_user.admin? && #user != current_user %> <%=link_to "deactivate", deactivate_path(user_id: #user), method: :post, data: { confirm: "Are you sure?" } %> <% end %>
Then in your controller:
def deactivate
user = User.find(params[:user_id])
if current_user.admin?
user.deactivate_account!
redirect_to users_path
else
redirect_to :back
end
end
And in your routes, something like:
post "/deactivate", to: "users#deactivate"
Anyway, I'm giving you a rough guide, but do read Hartl's tutorial, as your use case is almost covered there.
Good luck!
According to Rails convention:
PUT is used for updating an existing resource
POST is used for creating a new resource
So, you should make this a PUT request rather than POST as it is updating the user record.
You should define your route like this:
put 'deactivate/:id(.:format)', :to => 'users#deactivate', :as => :deactivate_user
And, in your user partial:
<%=link_to "Deactivate", deactivate_user_path(user), method: :put, data: { confirm: "You sure?" }%>
Everything should work now with your existing code.

Rails[Devise]: devise breaking navbar links

I have a Bootstrap navbar, but the tabs are generated at runtime. It's this way because they link to show/:id and a user can delete the record associated with that tab at any time. I created the links like this:
<% #groups.each do |group| %>
<li id=<%= group.id %>><%= link_to t("navbar." + group.name.singularize.downcase), :controller => 'groups', :action => 'show', :id => group.id %></li>
<% end %>
This works fine until I use Devise and attempt to get to /admins/sign_in. The navbar code is still exactly the same, but I get an UrlGenerationError:
No route matches {:action=>"show", :controller=>"devise/groups", :id=>4, :locale=>nil}
My guess is the error stems from the controller being "devise/groups" as that's the only difference I spot. Is there a way I can tell it to not prepend "devise"? Or do I have to write new routes for all these bits? If I have to add new routes, how can I use resources in routes?
I suspect Devise will also break other links on other pages that I had to code this way.
routes:
Rails.application.routes.draw do
devise_for :admins
get 'search/index'
get 'tags/:tag', to: "search#index", as: :tag
scope "(:locale)", :locale => /#{I18n.available_locales.join("|")}/ do
get 'home/index'
root :to => "home#index"
resources :brands
resources :faqs
resources :categories
resources :subgroups
resources :groups
end
UPDATE: I tried changing the link to the following
<% #groups.each do |group| %>
<li id=<%= group.id %>><%= link_to(t("navbar." + group.name.singularize.downcase), url_for(:controller => 'groups', :action => 'show', :id => group.id)) %></li>
<% end %>
But it still comes up with "devise/groups" as the controller when I access the sign-in page. After I sign in, there's no problem.
I have a strange "fix" but it certainly does not feel correct in the slightest. I created new Controllers that derive from Devise::[name]Controllers, and did the following to whatever methods I needed
def new
super
end
Then edited routes.rb
devise_for :admins, :controllers => {:[name] => "[name]"}
with a new :[name] => "[name]" pair for each Controller I had to make.
determined which ones I needed by looking at rake routes. Everything's working, but I'm sure there's a cleaner fix than this out there.
p.s. you may need to run rails g devise:views

Routing error for /users/Sign_out ; Devise signout doesnt work

I'm following this tutorial to build a dropbox like application
Build-a-dropbox-like-file-sharing-site-with-ruby-on-rails
I'm new to Ruby on Rails and still learning. According to the tutorial I used devise for authentication, But it has a problem that it doesn't let me sign out once signed in. I'm unable to figure out the solution for this.
I googled and tried to add this in routes.rb
routes.rb
Dropbox::Application.routes.draw do
#me devise_for :users
devise_for :users do get '/users/sign_out' => 'devise/sessions#destroy' end
root :to => "home#index"
end
I am unable to fix this. Please help.
In routing you have define 'GET' it should be 'DELETE'
Please change your routes to devise_for :users
I think the route for signing out is a DELETE method. This means that your sign out link needs to look like this <%= link_to "Sign out", destroy_user_session_path, :method => :delete %>. Yours doesn't include the :method => :delete part.
please also check your devise initializer file.
it should be define
#config/initializers/devise.rb
config.sign_out_via = :delete
It will work
Example rails-devise , Please clone this.
This should be enough:
devise_for :users
From your error
Routing error for /users/Sign_out
I see that you are using incorrect route, it should be
/users/sign_out
not
/users/Sign_out

Devise No route matches [GET] "/users/sign_out" from link with delete specified

So I looked around for a solution to this issue and most seem to say the same thing which hasn't done much to solve my problem. I've specified the delete method in the link but the routing error is saying it was a GET request. Any ideas why the link below would wind up making a overriding/ignoring the method declaration?
<%= link_to "sign out", destroy_user_session_path, :method => :delete %>
Routes
devise_for :users do
get 'logout' => 'sessions#destroy', :as => :destroy_user_session
get 'login' => 'devise/sessions#new'
end
In your config/initializers/devise.rb change the default HTTP method used to sign out a resource to :get. The default is :delete.
config.sign_out_via = :get
Don't use GET to destroy a session because it opens you up to CSFR, which isn't that big deal of a deal in this case - but still not a good thing to do). And, it doesn't follow REST conventions.
If you're using SSL for Devise routes, what's happening is when you try to sign out from an 'http' url, it's sending a DELETE request properly but then redirecting to the 'https' version via GET.
Fix this by adding (protocol: 'https') to the sign out url like so:
= link_to "Logout", destroy_user_session_url(protocol: 'https'), method: :delete
Note: it's important to use 'url' instead of 'path'.
Hope that helps.
What I did was change:
get 'logout' => 'sessions#destroy', :as => :destroy_user_session
to
delete 'logout' => 'sessions#destroy', :as => :destroy_user_session
and changed:
destroy_user_session_path
to
destroy_user_session_url
and I commented out:
config.sign_out_via = :get
in config/initializers/devise.rb because the default is :delete (which is conventional and secure).
Happy coding!
I think it's because you use 'get' instead a 'delete' in the declaration of route.
Try change 'get' by 'delete' in 'logout' route:
devise_for :users do
delete 'logout' => 'sessions#destroy', :as => :destroy_user_session
get 'login' => 'devise/sessions#new'
end
Check whether you have include jquery and jquery_ujs
<%= javascript_include_tag "jquery", "jquery_ujs" %>
If not include it. It is solve this problem.
In my case, using button_to instead of link_to solved my problem:
<%= button_to "Log out", destroy_user_session_path, method: 'delete' %>
This answer helped me.

ruby on rails button_to not activating the delete method

Hi im following the agile web development ebook and i cant seem to activate the logout action
here are the revelant parts (TAB key not working could not format to code)
rake routes
logout DELETE /logout(.:format) sessions#destroy
from the route file
controller :sessions do
get 'login' => :new
post 'login' => :create
delete 'logout' => :destroy
end
my controller
def destroy
session[:user_id] = user.id
redirect_to store_url , notice: "Logged out"
end
and my view (relevant part)
<%= button_to 'Logout', logout_path, method: :delete %>
the error message is
No route matches [GET] "/logout"
i know it should use delete method but nothing i do seems to help
You may need to add a match in your routes. Sorry that I don't have the book with me to refer to.
Put this above your controller :sessions ...
match 'logout' => 'sessions#destroy', :as => :logout
If you didn't put the above line, your logout path should be sessions_logout_path, not logout_path.
Reference:
http://guides.rubyonrails.org/routing.html#naming-routes
match '/logout' => 'sessions#destroy', :via => :delete
or
controller :sessions do
member do
delete :destroy, :as => :logout
end
end

Resources