I\'ve just upgraded an app from Rails 3 to Rails 4, and I\'m seeing a bunch of InvalidAuthenticityToken exceptions popping up. Digging in it looks like it is fairly common for o
In my rails 4.1.1 app I had the same problem. I solved it by adding this code to ApplicationController. I found this solution here.
rescue_from ActionController::InvalidAuthenticityToken, with: :redirect_to_referer_or_path
def redirect_to_referer_or_path
flash[:notice] = "Please try again."
redirect_to request.referer
end
This way any controller that inherits from ApplicationController will handle the error with a redirect to the page the form was submitted from with a flash message to give the user some indication of what went wrong. Note this uses the hash syntax introduced in Ruby 1.9. For older versions of Ruby you will need to use :with => :redirect_to_referer_or_path
Answer by Durrell is perfectly alright, I am just providing an alternative way to write the same thing. This needs to go in ApplicationController
.
rescue_from ActionController::InvalidAuthenticityToken do |_exception|
flash[:alert] = 'Please try again.'
redirect_back fallback_location: root_path
end
The solution to this problem can be divided into 2 phases. Phase 1 addresses the issue of ActionController::InvalidAuthenticityToken
error and phase 2 deals with the issue of long tabs waiting idly.
One way to go about is redirect the user back to their location before the error. For ex. if Alice has 3 tabs open, the first one expires and Alice logs in again in it because she was browsing on it. But when she moves to tab 3 which has URL 'http://example.com/ex' and submits a form. Now instead of displaying her an error we can redirect her back to 'http://example.com/ex' with her submitted form values already pre-filled in the form for easy use.
This can be achieved by following this approach:
1) ApplicationController - Add this function:
def handle_unverified_request
flash[:error] = 'Kindly retry.' # show this error in your layout
referrer_url = URI.parse(request.referrer) rescue URI.parse(some_default_url)
# need to have a default in case referrer is not given
# append the query string to the referrer url
referrer_url.query = Rack::Utils.parse_nested_query('').
merge(params[params.keys[2]]). # this may be different for you
to_query
# redirect to the referrer url with the modified query string
redirect_to referrer_url.to_s
end
2) You need to include a default value for all your form fields. It will be the name of that field.
...
<% f.text_field, name: 'email', placeholder: 'Email', value: params[:email] %>
...
This way whenever Alice will submit a form with wrong authenticity_token
she will be redirected back to her form with the original values she submitted and she will be shown a flash message that kindly retry your request.
Another way to go about is just redirect Alice back to the form which she submitted without any pre-filled values.
This approach can be achieved by:
1) ApplicationController - Add this function:
def handle_unverified_request
flash[:error] = 'Kindly retry.'
redirect_to :back
end
To tackle the problem of long awaited tabs you can take the help of SSEs. Rails 4 has ActionController::Live
for handling SSEs.
1) Add this to any controller:
include ActionController::Live
...
def sse
response.headers['Content-Type'] = 'text/event-stream'
sse = SSE.new(response.stream, retry: 2000, event: 'refresh') # change the time interval to your suiting
if user_signed_in? # check if user is signed-in or not
sse.write('none')
else
sse.write('refresh')
end
ensure
sse.close
end
2) Give the above function a GET
route in your routes file. Lets call this route '/sse'
3) Add this in your layout:
<% if user_signed_in? %> # check if user is signed-in or not
<script>
var evtSource = new EventSource("/sse");
evtSource.addEventListener('refresh', function(e){
if(e.data == 'refresh'){
window.location = window.location.href;
}
});
</script>
<% end %>
Note: using EventSource is not supported by all browsers. Please check out the Browser compatibility section.
Source: rails 4 redirect back with new params & MDN: Using server-sent events