Gracefully handling InvalidAuthenticityToken exceptions in Rails 4

前端 未结 3 1114
北恋
北恋 2021-02-04 02:39

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

3条回答
  •  感情败类
    2021-02-04 03:05

    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.

    Phase 1(1st variation)

    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.

    Phase 1(2nd variation)

    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
    

    Phase 2

    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
        
    <% 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

提交回复
热议问题