instrumentl / rails-cloudflare-turnstile

ISC License
23 stars 13 forks source link

The Cloudflare verification widget is not rendered when visiting the turbo links enabled page #63

Open yash-learner opened 1 year ago

yash-learner commented 1 year ago

I'm currently using your rails_cloudflare_turnstile gem in a Rails project and have encountered an issue. The gem seems to not work properly with pages using Turbolinks.

The Cloudflare widget is not rendered on a page which has turbolinks enabled, but the Cloudflare widget gets rendered on the same page on a full-page reload (refresh).

The things I tried

  content_tag(
    :script,
    src: js_src,
    async: async,
    "data-turbolinks-track": 'reload',
  ) { '' }

application.js

document.addEventListener("turbolinks:load", function () {
  let scriptSrc = "https://challenges.cloudflare.com/turnstile/v0/api.js";

  let existingScript = document.querySelector(`script[src="${scriptSrc}"]`);

  existingScript.setAttribute("data-turbolinks-track", "reload");
});

This can a problem because in the future if the version of Cloudflare is changed to v0 to v1 ..


2.

I had overided the method in cloudflare_turnstile.rb initializer

module RailsCloudflareTurnstile
  module ViewHelpers
    def cloudflare_turnstile_script_tag(async: true, defer: false)
      javascript = <<~JAVASCRIPT
        document.addEventListener("turbolinks:load", function() {
          let script = document.createElement("script");
          script.src = "#{RailsCloudflareTurnstile.enabled? ? js_src : mock_js}";
          script.async = #{async};
          script.defer = #{defer};
          script.dataset.turbolinksTrack = "reload";
          document.head.appendChild(script);
        });
      JAVASCRIPT

      content_tag(:script, javascript.html_safe)
    end
  end
end

I would like to ask if there's a workaround or a possible patch to make it compatible with Turbolinks. I believe this would greatly enhance the gem's versatility and usability for many Rails developers.

Looking forward to hearing from you soon. Thank you for your time and consideration.

AliOsm commented 1 year ago

This could be solved with the following:

  1. Create a Stimulus controller with the following content:
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    if (document.querySelector(".cf-turnstile") && window.turnstile) {
      window.turnstile.render(".cf-turnstile");
    }
  }
}
  1. Wrap cloudflare_turnstile in a div with data-controller="cloudflare-turnstile":
<div data-controller="cloudflare-turnstile">
  <%= cloudflare_turnstile %>
</div>

It works fine, what do you think?

yash-learner commented 1 year ago

Thanks @AliOsm, for the suggestion and please accept my apologies for the delayed response.

It works fine, and I feel it is a cleaner and better solution.

Thank you for sharing it.👍

PapePathe commented 6 months ago

It works fine, i feel like this should be in the readme.

jamesst20 commented 5 months ago

@Roguelazer

The proper fix is to tell turbo to simply reload the script

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer data-turbo-track="reload" data-turbo-temporary="true"></script>

Could you please let us add custom configuration for that and include documentation? Hotwire + Turbo is used a lot by Rails community it even ships by default with Rails 7 now.

Temporary patch that works. Add this in the initializer:

module RailsCloudflareTurnstileTurboPatch
  def cloudflare_turnstile_script_tag(async: true, defer: true)
    super.sub("></script>", " data-turbo-track=\"reload\" data-turbo-temporary=\"true\"></script>").html_safe
  end
end

RailsCloudflareTurnstile::ViewHelpers.prepend(RailsCloudflareTurnstileTurboPatch)

@yash-learner it seems you said you tried but it does work fine. Turbolinks has been long dead, you should consider upgrading to Turbo. I use Turbo v8

Edit

The trick was data-turbo-temporary="true"