DELETE method not being used on sign out in Devise - ruby-on-rails

I have Devise set up in my Rails application, but my sign out link:
<%= link_to "Sign out", destroy_user_session_path, method: :delete %>
is not working. The correct HTML seems to be generated:
<a rel="nofollow" data-method="delete" href="/users/sign_out">Sign out</a>
but there is no DELETE request being logged by Rails, only a 'GET /user/sign_out', which then throws an exception. What could be causing this?
Edit:
I've now discovered if I use button_to instead of link_to this works, so the issue certainly seems to be with the DELETE call not being generated client-side.

Related

No route matches [GET] "/users/sign_out" **Rails 5/Bootstrap 4**

I am running Rails 5 and updated Bootstrap to version 4 in an existing app which uses Devise.
Before updating Bootstrap, the routes were working fine. Now, when the user selects sign-out, they receive the following message:
No route matches [GET] "/users/sign_out"
Here is part of the header code:
<% if current_user %>
<a class=<%= link_to 'Classes', tracks_path %></a>
<a class=<%= link_to 'Edit profile', edit_user_registration_path %></a>
<a class=<%= link_to 'Sign out', destroy_user_session_path, method: :delete %></a>
And Rake Routes shows:
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
Is there a reason that the change to Bootstrap 4 would trigger this error? I have followed all of the instructions on the Bootstrap repo for installation.
The problem is you're rendering your link tags inside the class attribute:
<a class=<%= link_to 'Sign out', destroy_user_session_path, method: :delete %></a>
So that results in malformed output which ignores that you specify method: :delete. This is what you're looking for:
<%= link_to "Sign out", destroy_user_session_path,
method: :delete, class: 'nav-link' %>

ActionController::InvalidAuthenticityToken error in rails

I wanted to add some custom fields to devise authentication, so I followed a tutorial and did some changes. I unpacked the devise gem, added the fields to the views, and devise controller. I added the fields "first_name" and "last_name" to my users table. The changes didn't work. So I didn't want to spend much time on that, so I wanted to move on, I removed all the code I added to the devise gem sourcecode, created a migration to remove first_name, and last_name from users. Everything looked fine, I can move about on the site and everything. But as soon as I try to sign out, I get this error:
In the command line, the error also says "can't verify CSRF token auhtenticity"
This is the code I have in my layout view navbar for the user to sign out:
<% if user_signed_in? %>
<li><%= link_to "Sign out", destroy_user_session_path, method: :delete %></li>
<%else%>
<li>
<%= link_to "sign up" , new_user_registration_path %>
</li>
<li>
<%= link_to "Log in", new_user_session_path%>
</li>
<%end%>
I restarted the server and all that. The user is still signed in. I can't do anything to sign out. Is there a way to fix this?
To destroy a user session in devise, you have to do the following:
<%= link_to "Logout", destroy_user_session_path, :method => :delete %>
the hash ':method' will trigger delete action and sign the user out and destroy current session. Make sure your pointing to your "destroy_user_session_path", or the path you specified. You should be able to see what the name of the path is by using "rails routes" or "rake routes" command depending on what version of rails you're using.
Hope this helps.

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.

Rails 4 delete button logs me out and results in "Can't verify CSRF token authenticity"

I'm running Rails 4.2, Devise 3.4.1, and CanCan 1.6.10. When I try to delete resources via a standard delete button like the following one, I get signed out and redirected to the login page.
<a data-confirm="Are you sure?" class="btn-alert" rel="nofollow" data-method="delete" href="/admin/lots/6">Delete</a>
My dev log tells me it's because it "Can't verify CSRF token authenticity". The only way I can seem to get this to work is to change from a delete button to a form that posts to the delete action, but that's kind of dumb. I've done this in other Rails 4 apps so I'm pretty sure I'm doing it right.
index.html.erb
<% if can? :destroy, lot %>
<%= link_to "Delete", admin_lot_path(lot.id), method: :delete, data: {confirm: "Are you sure?"}, class: 'btn-alert' %>
<% end %>
lots_controller.rb
class Admin::LotsController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
def destroy
#lot.destroy
redirect_to admin_lots_path, notice: "Lot was successfully removed."
end
end`
Like I said, replacing the button with a form seems to work but this isn't ideal.
<%= form_for([:admin, lot], method: :delete) do |f| %>
<%= f.submit value: "Delete", class: 'btn-standard', data: {confirm: "Are you sure?"} %>
<% end %>
If I comment out before_filter :authenticate_user! and load_and_authorize_resource from the controller it works. I'm assuming the csrf token is not being sent along with this request like it would be in a form.
Does anybody have any ideas on what I can try? Willing to post more code if it would be helpful. This happens on all deletes in my application btw.
Update: Here's a snippet from development.log
Started DELETE "/admin/lots/6" for 127.0.0.1 at 2015-05-26 15:03:22 -0500
Processing by Admin::LotsController#destroy as HTML
Parameters: {"id"=>"6"}
Can't verify CSRF token authenticity
Use button_to instead of link_to.
button_to "Delete", admin_lot_path(lot.id), method: :delete, data: {confirm: "Are you sure?"}, class: 'btn-alert'
link_to produces this HTML which is missing the authenticity token,
<a data-confirm="Are you sure?" class="btn-alert" rel="nofollow" data-method="delete" href="/admin/lots/6">Delete</a>
while button_to produces
<form class="button_to" method="post" action="/admin/lots/6">
<input type="hidden" name="_method" value="delete">
<input data-confirm="Are you sure?" class="btn-alert" type="submit" value="Delete">
<input type="hidden" name="authenticity_token" value="1QajBKKUzoEtUqi6ZX8DsQtT9BfvKY/WVXAr4lu4qb+iLGMkLlsviNcctlGxyq+VrsMa+U9vmb4PAdaRFDKZVQ==">
</form>
You have to pass the csrf token as a parameter, example:
link_to "Delete", admin_lot_path(id: lot.id, authenticity_token: form_authenticity_token), method: :delete, data: {confirm: "Are you sure?"}, class: 'btn-alert'
"form_authenticity_token" is a convention method that returns the CSRF token. That will authenticate the request.
As per ActionController documentation all the Controller actions are protected from CSRF(Cross Site Request Forgery ) attacks, so either you need to include your token in rendered HTML or the other way is to include
protect_from_forgery unless: -> { request.format.json? } in your Application controller . This problem doesn't comes in GET request as you are not manipulating data over there but comes in POST,DELETE,PATCH methods.

How do I convert this a href into a Rails friendly link_to

I would like to convert this:
<a class="btn btn-google-plus" href="https://plus.google.com/share?url=SHAREMESSAGE" title="Share on Google+" target="_blank">
<i class="fa fa-google-plus"></i>
</a>
Into a Rails friendly link_to that not uses post.title in the URL and also includes a link to the current post.
In other words, I started by doing this in HTML like this:
<a class="btn btn-google-plus" href='https://plus.google.com/share?url=<%= "#{post.title} - Read more at #{post}" %>' title="Share on Google+" target="_blank">
<i class="fa fa-google-plus"></i>
</a>
The issue with this is that this generates a URL like this (the Twitter equivalent, but the principle is the same):
http://twitter.com/home?status=PNPYO%20saddened%20at%20passing%20of%20Roger%20Clarke%20-%20Read%20more%20at%20#<Post:0x00000101660e98>
Where it returns a Post object. The issue I ran into quickly, was that I wasn't quite sure how to generate a link_to within a link_to. Is that even possible?
This is how I want the final status on Twitter to look:
PNPYO saddened at passing of Roger Clarke - Read More at http://example.com/pnpyo-saddened-at-passing-of-roger-clarke
How do I achieve this in the most Rails-friendly way possible? I am not averse to just using regular a href tags, if it can't be done with a link_to helper. But either way, I still need to be able to generate a link_to within the status message.
You can achieve as follow :
<%= link_to "https://plus.google.com/share?url=#{post.title} - Read more at #{post}", :class => "btn btn-google-plus" :title => "Share on Google+" :target => "_blank" do %>
<i class="fa fa-google-plus"></i>
<% end %>
You don't want to call a link_to within a link_to, but you want to call an url_helper directly.
link_to in rails is a helper method which generates the necessary html code for links. Whether you want to use this convenience function or not, what you are searching for is a direct method to generate an url that you can concatenate into a string.
Simply use the following as the href for your anchor:
http://twitter.com/home?status=<%=u "#{post.title} - Read more at #{post_url(post)}" %>
(<%=u %> performs the url encoding of the string)

Resources