Google Tag Manager interfering with Rails UJS remote:true

504 Views Asked by At

I am including GTM in my <head> with the following:

<!-- Google Tag Manager -->
<script>
document.addEventListener('turbolinks:load', function(event) {
  var url = event.data.url;
  dataLayer.push({
    'event':'pageView',
    'virtualUrl': url
  });
});
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');
</script>
<!-- End Google Tag Manager -->

And in the <body> with

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

On my page, I have a link_to helper that deletes an image from the database using rails-ujs.

<%= link_to "Delete", destroy_image_path(image), remote: true, method: "delete" %>

When I remove the GTM code from the page, the Delete link performs as expected.

However, with the GTM code in place, clicking the link results in a Routing Error as it attempts to make a GET request.

No route matches [GET] "/..."

It seems to me that GTM is interfering with rails-ujs but I'm unsure of the best way to run this down.

Edit: I have tried this code with and without the turbolinks:load listener with the same failed result.

1

There are 1 best solutions below

0
On

I had to do the following:

(function($) {
  var handlerElement = document.body;
  var selector = 'a[data-method=put],a[data-method=patch],a[data-method=post],a[data-method=delete]';
  var events = ['click', 'mousedown', 'mouseup'];
  var namespacedEvents = $.map(events, function(event) {
    return [event, 'disable_method_links'].join('.');
  });
  var handlers;

  $(handlerElement).on(namespacedEvents.join(' '), selector, function(e) {
    e.preventDefault();
  });
})(jQuery);

Basically, GTM adds handlers for all of the target anchor tags, delegated from the document node, and wraps the existing handlers, checking whether they prevent the default action / stop propagation, I'm not sure exactly what's causing it, but I think it's that GTM is loading before my events are registered, and not detecting that the default action is prevented, so delegating from the body tag and preventing the default action there ensures that your event is hit before any GTM events (which, as mentioned, are registered on the document node).

I'm not sure whether the mousedown/mouseup events are necessary, but I'm posting this in a hurry before I leave for a long weekend so don't have time to check.

Also, I added a defer tag to the script tag that GTM generates and injects into the document, but I don't think that is necessary either, again, haven't tested.

Also see: https://www.simoahava.com/gtm-tips/fix-problems-with-gtm-listeners/