Unable to log out of clearance gem - ruby-on-rails

I have recently move my project away from the somewhat bloat devise to clearance, though I am experiencing troubles when attempting to log out
I am currently get the error of the route not existing
No route matches [GET] "/sign_out"
routes
resources :passwords, controller: "clearance/passwords", only: [:create, :new]
resource :session, controller: "clearance/sessions", only: [:create]
resources :users, controller: "clearance/users", only: [:create] do
resource :password,
controller: "clearance/passwords",
only: [:create, :edit, :update]
end
get "/sign_in" => "clearance/sessions#new", as: "sign_in"
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
get "/sign_up" => "clearance/users#new", as: "sign_up"
constraints Clearance::Constraints::SignedIn.new do
root :to => 'shopping/merchants#index', as: :signed_in_root
end
constraints Clearance::Constraints::SignedOut.new do
root to: 'clearance/sessions#new'
end
view
= link_to sign_out_path, method: :delete, class: 'mdl-navigation__link' do
i.material-icons> exit_to_app
= t('.log_out')

The message is telling you there is not get route for sign_out, which is correct. You must do a delete. This means, despite your efforts with method: :delete, the link is executing a get request. There's something about your link_to that is not correct. It likely has to do with passing method while using the block form of link_to.
Try:
<%= button_to "Sign Out", sign_out_path, method: :delete %>
If that works, try:
<%= link_to "Sign Out", sign_out_path, method: :delete %>
If both of those work, then the issue is indeed with the way you're using the block form of the link_to helper and has nothing to do with Clearance.

I thought I'd follow up on this with a little more insights for anyone who found themselves here still wondering exactly what is behind this.
As suggested by Derek, to get this sorted, you'll need to use the button_to instead of link_to, as follows:
<%= button_to "Sign Out", sign_out_path, method: :delete %>
Why can't I just use link_to?
So more insights into this are delivered by this previous SO. Essentially, you can't make a link operate as a DELETE method, only GET.
If you have a look at how link_to is actually rendered in HTML on the page (after Ruby works its magic), you'll see the following:
<a rel="nofollow" data-method="delete" href="/sign_out">Sign out</a>
And it's clear that data-method="delete" is still not going to cut it, and still runs the request as GET.
But I don't want a button, I want a link?
Your best bet is to look at some CSS on the element to get it back to looking like a link, otherwise, you'll need to go the Javascript route.
Non-RESTFUL Clearance Centric Dirty Hack - Not Advised!
Using link_to, change your routes.rb where the clearance route currently says:
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
to:
get "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
It'll route the GET request to the destroy action on the Clerance controller. I dare say this is not advised and Derek could support why this was not supported in the first place (Devise gem does support this dirty hack)

Related

No route matches [GET]. Trying to [PUT]. Rake routes shows this path with put and patch

routes.rb
namespace :scheduling do
resources :scheduling_details, only: [:create, :destroy, :update, :index]
do
rake routes
scheduling_scheduling_detail
PATCH /scheduling/scheduling_details/:id(.:format)
scheduling/scheduling_details#update
PUT /scheduling/scheduling_details/:id(.:format)
scheduling/scheduling_details#update
view
<%= link_to "Yes", scheduling_scheduling_detail_path(#scheduling_detail) %>
Error. No route matches [GET] "/scheduling/scheduling_details/6256"
Notice the plural there. I'm not sure why it's trying to access the plural url when I didn't use the plural path shortcut.
So I try to use the manual url instead of the path shortcut
<%= link_to "Yes", "/scheduling/scheduling_detail/#{#scheduling_detail}" %>
Error: No route matches [GET] "/scheduling/scheduling_detail"
Maybe try with the id?
<%= link_to "Yes", "/scheduling/scheduling_detail/#{#scheduling_detail.id}" %>
Error: No route matches [GET] "/scheduling/scheduling_detail/6256"
Try adding :show to your array, like so:
namespace :scheduling do
resources :scheduling_details, only: [:create, :destroy, :update, :index, :show]
do
And make sure you have a show method in your controller and a view.
As per your routes printout:
Your paths are plural. The issue is that you don’t have a GET method, which corresponds to the show view.
You’ll want to change your link_to method to PUT or PATCH.
Something like this in your view should work:
<%= link_to "Yes", scheduling_scheduling_detail_path(#scheduling_detail), method: :put %>
https://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to
You are specifying the wrong path using scheduling_scheduling_detail you are specifying the #GET Request you need to use the update_ prefix to specify PUT/PATCH. The following would do the trick.
<%= link_to "Yes", update_scheduling_scheduling_detail_path(#scheduling_detail) %>

In a Rails app, how can I use a button to run a non-restful controller method? Getting no routes error

In my application I have a link_to helper method:
<%= link_to "Downgrade", :controller => :subscriptions, :action => :downgrade, class: "btn btn-primary", remote: true %>
In my controller I have this code:
class SubscriptionsController < ApplicationController
respond_to :js
def downgrade
# some code
end
end
I am getting this error:
No route matches {:action=>"downgrade", :class=>"btn btn-primary", :controller=>"devise/subscriptions"}
Here is my routes.rb code:
Rails.application.routes.draw do
resources :wikis
devise_for :users
resources :users, only: [:update]
root to: 'welcome#index'
resources :charges, only: [:new, :create]
end
I know Rails is expecting a route for this but I don't know what route I would use since the method isn't a restful verb. Maybe there is another way without using the link_to which allows me to directly call a controller method from a view? Maybe I need to restructure where things are as well. Any help is appreciated.
Let me know if there is more code you would need to fully assess this situation.
Basic setup
first you need to setup your route in routes.rb
get 'downgrade' => 'subscriptions#downgrade', :as => :downgrade_subscription
This will redirect /downgrade to your subscriptions controller & downgrade action. The as option saves this route into a variable you can call from all your views.
<%= link_to "Downgrade", downgrade_subscriptions_path, class: "btn btn-primary", remote: true %>
Further configuration
You can also nest this route inside your subscription resources like so:
resources :subscriptions do
get 'downgrade' => 'subscriptions#downgrade', :as => :downgrade_subscription
end
This will create the path /subscriptions/downgrade instead of /downgrade.
The Rails Docs on routing does a great job explaining this in more detail. Definitely check it out!
or you can try this on your routes.rb
match '/downgrade_subscription', :to => 'subscriptioni#downgrade', :via => :get

Rails link_to nested resources

I created a nested resources but my link_to shows undefined method 'model_name' for Parking::ActiveRecord_Relation:Class in the browser. I did it wrongly, obviously. How can I correct it?
index.rb
<%= link_to 'Create new parking', new_parking_path %></br>
<%= link_to 'Rent place', [#parking, #place_rent]%>
routes.rb
resources :parkings do
resources :place_rents, :only => [:new, :create]
end
Either #parking or #place_rent is a relation (collection) and not a particular model which you would need to build a route. Depending on what is behind these variables you might need a #first or whole different query.

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.

link_to helper giving me ?id= instead of / (slash)

I have this in my routes.rb:
resources :profiles, :only => :show
I'm building a link like this: <%= link_to( "profile", profile_path(13)) %> and it's giving me a url of /profile?id=13 - I want it to give me /profiles/13 (as that one works).
What am I doing wrong?
Rake routes result for this resource:
GET /profiles/:id(.:format) profiles#show

Resources