Reputation: 5270
I was Making a AJAX POST request to rails with this code:
var new_note = {
title: "New note"
};
$.post('/notes.json',
{
auth_token: auth_token,
note: new_note
},
function(data, textStatus, jqXHR){
console.log(textStatus);
console.log(jqXHR);
var createdNoteIndex = self.notes.push(new Note());
self.openNote(self.notes()[createdNoteIndex - 1]);
}, "json")
.error(function(jqXHR, textStatus, errorThrown){
alert("error");
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
});
and I forgot to insert the csrf token so I thought the create action was going to fail:
# POST /notes.json
def create
@note = current_user.notes.new(params[:note])
if @note.save
respond_with { render json: @note, status: :created, location: @note }
else
respond_with { render json: @note.errors, status: :unprocessable_entity }
end
end
but the record in the database has been created anyway while the requested ended in a 500 error:
Started POST "/notes.json" for 127.0.0.1 at 2012-04-30 15:26:33 +0200
Processing by NotesController#create as JSON
Parameters: {"auth_token"=>"zJzKxPnvx5dQDTcFWi5k", "note"=>{"title"=>"New note"}}
MONGODB (0ms) taccuino_development['users'].find({:_id=>BSON::ObjectId('4f9c670a809ad20869000002')}).limit(-1).sort([[:_id, :asc]])
MONGODB (0ms) taccuino_development['notes'].insert([{"_id"=>BSON::ObjectId('4f9e9309809ad223f5000007'), "title"=>"New note", "user_id"=>BSON::ObjectId('4f9c670a809ad20869000002')}])
Completed 500 Internal Server Error in 8ms
AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".):
app/controllers/notes_controller.rb:26:in `create'
Rendered /home/matteo/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.2.3/lib/action_dispatch/middleware/templates/rescues/_trace.erb (4.2ms)
Rendered /home/matteo/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.2.3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.5ms)
Rendered /home/matteo/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.2.3/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (14.8ms)
I've not disabled the csrf protection so It should have given an error about the missing of the token but it hasn't...
EDIT:
after readng the two answers I have:
added this code to replace the jquery_ui function for csrf token and setting also the auth_token for devise:
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (settings.crossDomain) return;
var csrf_token = $('meta[name="csrf-token"]').attr('content');
var auth_token = $('meta[name="auth_token"]').attr('content');
xhr.setRequestHeader('X-CSRF-Token', csrf_token);
xhr.setRequestHeader('auth_token', auth_token);
}
});
removed the before_file authenticate_user! from the controller and replaced the create action releated to the current_user with a different one:
def create
@note = Note.new(params[:note])
if @note.save
respond_with { render json: @note, status: :created }
else
respond_with { render json: @note.errors, status: :unprocessable_entity }
end
end
Then I've disabled the CSRF protection but i'm still getting the same error... so the probelm is another but i really can't understand what can cause a double redirection since the record is correctly created in the database...
Upvotes: 2
Views: 1398
Reputation: 16284
If you've included jquery_ujs.js
into your application, the CSRF token will automatically be added to AJAX requests. You can see that here.
This also has nothing to do with your DoubleRenderError
btw. That's your incorrect use of respond_with
.
Edit:
Don't disable CSRF protection. Just don't.
You don't need to add the token yourself, everything should go automatically.
The reason why your action causes an error is because of respond_with
. If you're only responding to json requests, this is how it should look:
# POST /notes.json
def create
@note = current_user.notes.new(params[:note])
if @note.save
render json: @note, status: :created, location: @note
else
render json: @note.errors, status: :unprocessable_entity
end
end
But, because Rails already knows this pattern (it's a convention), you can shorten it to:
respond_to :json #, :html, :xml (optionally)
def create
@note = current_user.notes.create(params[:note])
respond_with @note
end
More details about respond_with
are here.
Upvotes: 2
Reputation: 84172
The behaviour triggered by a missing or invalid csrf token changed about a year or so ago. Rather than raising an exception, the new behaviour is to reset the session, so the request is processed as if the user was not logged in.
You can control this behaviour by defining handle_unverified_request
and implementing the desired behaviour there.
Upvotes: 0