0

QUICK BACKGROUND

I have a model where a facility has_many managers through relationships. The relationship model holds one additional attribute, admin, which is a boolean. Then, for each facility, I have a page that allows an admin/some user to mark managers's as admin or not. They do this through checkboxes. I am using devise for managers. Everything is pretty much done like the first 2 minutes of this railscast:

http://railscasts.com/episodes/165-edit-multiple-revised?view=comments

THE PROBLEM(S)

The issue is, when I submit the form_tag, I get:

1. WARNING: Can't verify CSRF token authenticity

2. It then resets my user session (logs me out of devise), so I have to log back in to continue working.

If I remove protect from forgery from the application controller, everything works smoothly but obviously I don't want to do that as my fix.

So, how can I avoid this CSFR issue with form_tag?

THE FORM (updated)

<%= form_tag admin_relationships_path, method: :put do %>
  <table>
    <tr>
    <th></th>
    <th>Person Name</th>
    <th>Admin</th>
    </tr>

<% @relationships.each do |relationship| %>
   <tr>
   <td><%= check_box_tag "relationship_ids[]", relationship.id %></td>
   **<%= hidden_field_tag :authenticity_token, form_authenticity_token %>**        
   <td><%= User.find(relationship.user_id).full_name %></td>
   <td><%= relationship.admin ? "Yes" : "No" %></td>

   <td><%= link_to 'Remove', relationship, method: :delete, **remote: true** %></td>

   </tr>
 <% end %>
  </table>

   <%= submit_tag "Make Checked Admins" %>
 <% end %>

The contoller.

class RelationshipsController < ApplicationController

  def destroy
    @relationship = Relationship.find(params[:id])
    @relationship.destroy

    respond_to do |format|
      format.html { redirect_to "/facilities/1679/invite", notice: " Manager has been deleted." }
      format.json { head :no_content }
  end
end

The log.

Started DELETE "/relationships/52" for 127.0.0.1 at 2013-11-26 14:30:11 -0500
Processing by RelationshipsController#destroy as JS
Parameters: {"id"=>"52"}
WARNING: Can't verify CSRF token authenticity
  User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 38 LIMIT 1
  (0.1ms)  BEGIN
  (0.1ms)  COMMIT
 Relationship Load (0.2ms)  SELECT `relationships`.* FROM `relationships` WHERE `relationships`.`id` = 52 LIMIT 1
  (0.1ms)  BEGIN
 SQL (0.2ms)  DELETE FROM `relationships` WHERE `relationships`.`id` = 52
  (0.4ms)  COMMIT
 Redirected to http://localhost:3000/facilities/1679/invite
 Completed 302 Found in 10ms (ActiveRecord: 1.6ms)


 Started DELETE "/facilities/1679/invite" for 127.0.0.1 at 2013-11-26 14:30:11 -0500

 ActionController::RoutingError (No route matches [DELETE] "/facilities/1679/invite"):

Request Headers:

Accept, Accept-Encoding, Accept-Language, Connection, Cookie, Host, Origin, Referer, User-Agent, X-Requested-With

THE ANSWER

As the poster below mentioned, my CSFR token was not being received on the page. Although, I had the <%= csrf_meta_tag %> in my application layout and admin layout, and I was actually rendering the application layout, the form was on a Devise page.

So I needed to place the <%= csrf_meta_tag %> code in devise.html.erb. You can find the troubleshooting below.

miler350
  • 1,411
  • 11
  • 15

2 Answers2

3

Be sure you either have this in your application layout in the head section:

<%= csrf_meta_tag %>

Or this hidden field in your form:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
DiegoSalazar
  • 13,361
  • 2
  • 38
  • 55
3

Try adding this to aplication.js:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});

Answered here: WARNING: Can't verify CSRF token authenticity rails

Community
  • 1
  • 1
DiegoSalazar
  • 13,361
  • 2
  • 38
  • 55
  • Still not working, do I need to add the before send method too? And just to state it, I am restarting the server each time. – miler350 Nov 26 '13 at 19:49
  • No, it's either or. What version of Rails are you using? If you're on 3.1 try this answer: http://stackoverflow.com/questions/7203304/warning-cant-verify-csrf-token-authenticity-rails#answer-8798687 – DiegoSalazar Nov 26 '13 at 19:58
  • I don't know what the issue is man. That isn't working either. The app uses 3.2.11. – miler350 Nov 26 '13 at 20:06
  • Also, I commented out the `protect from forgery` just to see if everything worked smoothly. The Ajax link that I added with remote: true just sits there after the click, I have to reload the page to see the deleted item removed from the list. So maybe js isn't being accepted or something. – miler350 Nov 26 '13 at 20:12
  • Can you go into the network tab of your web inspector (e.g. firebug) and see what the requests headers are when you click the delete link? Make sure there's a header for X-CSRF-Token. – DiegoSalazar Nov 26 '13 at 20:13
  • you have to change format.json to format.js and return a js.erb template which handles removing the item from the DOM. – DiegoSalazar Nov 26 '13 at 20:14
  • I added the request headers to the bottom of the original post. I changed to format.js but did not supply a js.erb template. If you could kindly explain that part, it'd be appreciated. – miler350 Nov 26 '13 at 20:29
  • Your headers are missing the csrf header, try using the beforeSend function instead and see if that puts the header in the request properly. As for the js.erb template: If you just write format.js within your respond_to block, Rails will look for a template with the same action name (e.g. app/views/relationships/destroy.js.erb) and within that template write some js: $('tr#<%= dom_id(@relationship) %>).remove(); But for that to work you need to add the id to the within @relationships.each: – DiegoSalazar Nov 26 '13 at 21:09
  • You solved this for me. I still have the ajax issue but that is something I can worry about separately. The csrf is fixed. Please see the bottom of the post. – miler350 Nov 26 '13 at 21:29
  • Jesus christ this was frustrating. I was sending the token in the AJAX form itself and nothing worked. Adding it as a header worked even though it didnt work in the form. very weird... glad i saw this answer, i was going insane – Tallboy Jan 25 '17 at 00:31