Routing to show action on logout - ruby-on-rails

I have a logout link that should be routing to users#do_logout but no matter what I do, if I click the link, it routes to the users#show. Here is the code:
Route:
resources :users do
member do
get :profile
post :profile
end
collection do
get "signup", to: 'users#new'
get "login"
post "do_login"
post "do_logout"
end
end
Link:
li = link_to "Sign Out", do_logout_users_path
Users controller action:
def do_logout
session[:user_id] = nil
redirect_to :root
end
Any help would be much appreciated. This is driving me insane.

Your code is not working because, you have set up a POST route for do_logout and your Sign Out link is making a GET request.
To do a POST request from the view, you have to create a form
= form_tag do_logout_users_path do
= submit_tag 'Sign Out'
OR
You could use delete method for this
in routes
delete "do_logout"
and the link
= link_to "Sign Out", do_logout_users_path, :method => :delete

Related

Rails run :get route within /new and /edit _form

I have a _form for new and edit for a #Giveaway object. Within this form I have a field for a random winner.
I want to populate this field by calling the method giveaways#random_winner with <%= button_to "Randomly Pick Winner!", {:action => 'choose_winner'}, :method => :get %>, but I am getting this error No route matches {:action=>"choose_winner", :controller=>"giveaways"} when loading /giveaways/new.
Here is my controller:
def choose_winner
random_winner = SubscriberUser.where(user_id: current_user.id).pluck(:subscriber_id).sample(1)
session[:random_winner] = random_winner
redirect_to :back
end
Here are the routes that I have tried. I'm not very good at non-scaffold routes yet:
resources :giveaways do
member do
get 'choose_winner' => 'giveaways#choose_winner'
#tried get :choose_winner, as: :choose_winner
#tried get 'new/choose_winner'
#tried get 'choose_winner'
#tried get 'choose_winner', to: 'giveaways#choose_winner', as: 'choose_winner'
end
end
Question -- Why is the page not loading when I have defined the controller and action in the route? Will I have to reload the page when I do run that route... is there a better way to get at this data?
Your routes.rb is close
resources :giveaways do
member do
get :choose_winner
end
end
And then I would use a Rails route helper so you don't have to worry about setting the action/controller yourself.
<%= button_to "Randomly Pick Winner", choose_winner_giveaway_path(#giveaway), method: :get %>

Ruby-on-rails - Destroy - Error: No route matches [GET]

I am using destroy
In my view, I have:
#delete_archive_modal.modal.fade
.modal-header
%h3
%i.icon-exclamation-sign
Attention
.modal-body
%p= "Are you sure you want to delete this portal?"
.modal-footer
%a.btn{"data-dismiss" => "modal", :href => "#"} Cancel
= link_to 'Delete', delete_portal_path(portal)
Routes:
resources :portals do
resources :pill_tabs, only: [:show, :edit]
resources :page_urls do
collection do
get :redirects
end
end
resources :zero_touch_configs do
member do
get :history
end
end
member do
get :navigation
get :history
get :sitemap
get :url_list
post :generate_sitemap
post :add_modules
post :archive
post :delete
end
collection do
get :index, path: '/'
get :new, path: '/new(/:portal_type)'
get :accessible_sites
get :archive_index
get :delete
end
And in my controller:
def destroy
#portal = Portal.find(params[:id])
#portal.destroy
flash[:notice] = 'Portal deleted successfully.'
redirect_to action: :archive_index
end
routes:
portals GET /portals(.:format) portals#index
GET /portals/new(/:portal_type)(.:format) portals#new
accessible_sites_portals GET /portals/accessible_sites(.:format) portals#accessible_sites
archive_index_portals GET /portals/archive_index(.:format) portals#archive_index
delete_portals GET /portals/delete(.:format) portals#delete
history_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id/history(.:format) stack_wrappers#history
drafts_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id/drafts(.:format) stack_wrappers#drafts
purge_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id/purge(.:format) stack_wrappers#purge
all_drafts_portal_stack_wrappers GET /portals/:portal_id/stack_wrappers/drafts(.:format) stack_wrappers#all_drafts
portal_stack_wrappers GET /portals/:portal_id/stack_wrappers(.:format) stack_wrappers#index
POST /portals/:portal_id/stack_wrappers(.:format) stack_wrappers#create
new_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/new(.:format) stack_wrappers#new
edit_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id/edit(.:format) stack_wrappers#edit
portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id(.:format) stack_wrappers#show
PATCH /portals/:portal_id/stack_wrappers/:id(.:format) stack_wrappers#update
PUT /portals/:portal_id/stack_wrappers/:id(.:format) stack_wrappers#update
DELETE /portals/:portal_id/stack_wrappers/:id(.:format) stack_wrappers#destroy
history_portal_config_bundle GET /portals/:portal_id/config_bundles/:id/history(.:format) config_bundles#history
portal_config_bundles GET /portals/:portal_id/config_bundles(.:format) config_bundles#index
POST /portals/:portal_id/config_bundles(.:format) config_bundles#create
new_portal_config_bundle GET /portals/:portal_id/config_bundles/new(.:format) config_bundles#new
edit_portal_config_bundle GET /portals/:portal_id/config_bundles/:id/edit(.:format) config_bundles#edit
portal_config_bundle GET /portals/:portal_id/config_bundles/:id(.:format)
But I am getting a routing error and don't know where to go from here...
No route matches [GET] "/portals/asdg/delete"
Can anyone share a guide or point me to documentation that helps me understand what's wrong here?
Try
= link_to 'Delete', portal_path(portal), method: :delete
Here are the all 7 routes for portal
portals GET /portals(.:format) portals#index
POST /portals(.:format) portals#create
new_portal GET /portals/new(.:format) portals#new
edit_portal GET /portals/:id/edit(.:format) portals#edit
portal GET /portals/:id(.:format) portals#show
PATCH /portals/:id(.:format) portals#update
PUT /portals/:id(.:format) portals#update
DELETE /portals/:id(.:format) portals#destroy
And in your routes you have delete_portal path will exist because of
member do
post :delete
end
If you want to call this then you have do define method for this action in your controller and call this path with method: :post
But in RESTful routes delete action have always DELETE method, see in above routes.
There are two issues in your link_to tag.
You used delete_portal_path(portal) but if you run rake routes on your console you will see no such route exist. it have portal_path(portal).
You need to specify method type in route in case of Show(GET default), update(PUT) and delete(DELETE). Because all share same path portal_path(portal).
So your final route should be:
= link_to 'Delete', portal_path(portal), method: :delete
More detail here
You need to define http method when you use delete
= link_to 'Delete', portal_path(portal), method: :delete
It will work.

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 error (Couldn't find User with 'id'=logout) with Postgres

what are the possible solutions for (Couldn't find User with 'id'=logout)?. I appreciate any input. All what I could find is a reference to a bug. Thanks in advance.
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=logout):
app/controllers/users_controller.rb:16:in `show'
users_controller.rb
line 15: def show
line 16: #user = User.find(params[:id])
line 17: end
routes.rb
delete 'logout' => 'sessions#destroy'
views/layout/application.html.erb
<% if logged_in? %>
<li><%= link_to current_user.name, current_user %></li>
<li><%= link_to "Log out", logout_path, method: :delete %></li>
<% else %>
<li><%= link_to "Log in", login_path %></li>
<% end %>
So you're clicking the URL generated by logout_path (so, /logout?) and instead of going to your sessions#destroy action it's going to your users#show action and failing because your action is being given the string "logout" in params[:id]
This is going to be caused by another route earlier in your routes.rb file that is shadowing the route that you've shown in your question. Eg. you might have something like this:
resources :users, path: '/'
...or perhaps you have a normal users resource but then your delete line nested inside a users namespace or something:
resources :users
# then lower in your file something like...
namespace :users do
delete 'logout' => 'sessions#destroy'
end
Update
Neither of those things lead to exactly what you're seeing, so if the above doesn't point you in the right direction then please add to your question your full config/routes.rb file and/or the output of rake routes
For some reason Firefox wasn't sending http delete request when clicking logout, but a get, so had to add one line to routes.rb to handle http get request for logout. Special thanks goes to John!

Couldn't find User with id=sign_out

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.

Resources