Module: Controllers::PostRedirectable

Extended by:
ActiveSupport::Concern
Defined in:
app/concerns/controllers/post_redirectable.rb

Overview

Renders a self-submitting HTML form that POSTs to a target URL. Replaces
the unmaintained repost gem (last released 2017) with a small inline
implementation.

Used for OmniAuth provider authorization endpoints that require POST
(with the CSRF token already in the URL via authenticity_token=).

Usage:
redirect_post(omniauth_authorize_path(...))
redirect_post(url, params: { foo: 'bar' })

The form auto-submits via JavaScript on load. A no-script fallback
("Continue" button) is rendered for clients without JS. CSP-friendly:
uses request.content_security_policy_nonce on the script tag when
CSP is configured (no-op when it isn't).

Instance Method Summary collapse

Instance Method Details

#redirect_post(url, params: {}) ⇒ void

This method returns an undefined value.

Renders a self-submitting HTML form that POSTs to the target URL.

The form auto-submits via JavaScript on load; a no-script "Continue"
button fallback is included for clients without JS. The inline script
carries the request's CSP nonce when a content security policy is
configured.

Parameters:

  • url (String)

    the URL the form POSTs to (CSRF token already embedded)

  • params (Hash) (defaults to: {})

    additional hidden form fields to include



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/concerns/controllers/post_redirectable.rb', line 31

def redirect_post(url, params: {})
  helpers = ActionController::Base.helpers
  nonce = request.content_security_policy_nonce

  fields = params.map { |k, v| helpers.tag.input(type: 'hidden', name: k.to_s, value: v.to_s) }.join.html_safe
  form_attrs = { id: 'post-redirect', method: 'post', action: url }
  script_attrs = { nonce: nonce }.compact

  body = helpers.safe_join([
                             '<!DOCTYPE html>'.html_safe,
                             helpers.tag.html do
                               helpers.safe_join([
                                                   helpers.tag.head { helpers.tag.title('Redirecting…') },
                                                   helpers.tag.body do
                                                     helpers.safe_join([
                                                                         helpers.tag.form(**form_attrs) do
                                                                           helpers.safe_join([
                                                                                               fields,
                                                                                               helpers.tag.noscript { helpers.tag.button('Continue', type: 'submit') }
                                                                                             ])
                                                                         end,
                                                                         helpers.tag.script(
                                                                           "document.getElementById('post-redirect').submit();".html_safe,
                                                                           **script_attrs
                                                                         )
                                                                       ])
                                                   end
                                                 ])
                             end
                           ])

  render html: body, content_type: 'text/html'
end