Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Devise + Rails 3.0.4 ends session after AJAX request

I have an action triggered by an AJAX request generated by Ajax.InPlaceEditor or InPlaceCollectionEditor like this:

new Ajax.InPlaceCollectionEditor('agent_email', 'inspections/<%= @inspection.id %>/update_field', 
{
collection: [<% @agents.each do |agent| %>
        '<%= agent.email %>',           
        <% end %>],
    okText: 'Update',
    cancelText: 'Never mind',
    savingText: 'Updating...'

});

At the other end, the action contains this:

def update_field
  --some code here--
  if success
    puts "stored change"
    render :text => result
  else
    puts "did note change store"
    render :text => inspection.errors.to_json, :status => 500
  end
end

Once any of the render methods are reached, the session expires, and next time the user send a request, Devise sends them to the logon on page.

Even though I am exempting update_field from authentication (before_filter :authenticate_user!, :except => :update_field), the session is still getting reset.

I have looked at the answer at a very similar question at Devise session immediately expiring on .js call [AJAX], but it is not solving my particular problem.

Any ideas?

like image 326
futureshocked Avatar asked Feb 26 '11 00:02

futureshocked


Video Answer


1 Answers

I got this to work by getting the code from http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails (prototype-snippet.js):

/*
 * Registers a callback which copies the csrf token into the
 * X-CSRF-Token header with each ajax request.  Necessary to 
 * work with rails applications which have fixed
 * CVE-2011-0447
*/

Ajax.Responders.register({
onCreate: function(request) {
  var csrf_meta_tag = $$('meta[name=csrf-token]')[0];

  if (csrf_meta_tag) {
    var header = 'X-CSRF-Token',
        token = csrf_meta_tag.readAttribute('content');

    if (!request.options.requestHeaders) {
      request.options.requestHeaders = {};
    }
    request.options.requestHeaders[header] = token;
  }
}
});

... within a Javascript block in my application.html.erb:

<script type="text/javascript">
  (... the code from above)
</script>

Also don't forget to add:

<%= csrf_meta_tag %>

in the same file towards the top (if not already there).

The document "CSRF Protection Bypass in Ruby on Rails" explains why this works.

like image 109
futureshocked Avatar answered Nov 06 '22 20:11

futureshocked