Skip to content

Commit

Permalink
feat: support Google Tag Manager and Google Tags via an env variable (#…
Browse files Browse the repository at this point in the history
…455)

This is based on the different patterns we've used over the years for
supporting this in our apps - in the end I've gone with having a
dedicated analytics partial for "head" and "body" to provide a dedicated
grouping that'll also hopefully encourage people to think about the
situation if they find these files growing significantly.

Resolves #439

---------

Co-authored-by: Eoin Kelly <[email protected]>
  • Loading branch information
G-Rath and eoinkelly authored Sep 1, 2024
1 parent 67f99a5 commit 086c9df
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 6 deletions.
3 changes: 1 addition & 2 deletions variants/backend-base/app/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

# Configure app/views
template "variants/backend-base/app/views/layouts/application.html.erb", "app/views/layouts/application.html.erb", force: true
copy_file "variants/backend-base/app/views/application/_flash.html.erb", "app/views/application/_flash.html.erb"
copy_file "variants/backend-base/app/views/application/_header.html.erb", "app/views/application/_header.html.erb"
directory "variants/backend-base/app/views/application", "app/views/application"
copy_file "variants/backend-base/app/views/home/index.html.erb", "app/views/home/index.html.erb"

# Configure app/helpers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<%# analytics configuration that goes in the <body> %>

<% google_analytics_id = Rails.application.config.app.google_analytics_id %>

<% if google_analytics_id&.start_with?("GTM-") %>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=<%= google_analytics_id %>"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<%# analytics configuration that goes in the <head> %>

<% google_analytics_id = Rails.application.config.app.google_analytics_id %>

<% if google_analytics_id&.start_with?("GTM-") %>
<!-- Google Tag Manager -->
<%= javascript_tag nonce: true, defer: true do -%>
(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;var n=d.querySelector('[nonce]');
n&&j.setAttribute('nonce',n.nonce||n.getAttribute('nonce'));f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','<%= google_analytics_id %>');
<% end -%>
<!-- End Google Tag Manager -->
<% end %>

<% if google_analytics_id&.start_with?("G-") %>
<!-- Google tag (gtag.js) -->
<%= javascript_include_tag("https://www.googletagmanager.com/gtag/js?id=#{google_analytics_id}", nonce: true, defer: false) -%>
<%= javascript_tag nonce: true, defer: true do -%>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());

gtag('config', '<%= google_analytics_id %>');
<% end -%>
<% end %>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<%= app_const_base.titleize %>
</title>

<%%= render "application/analytics/head" %>

<%%= csrf_meta_tags %>
<%%= csp_meta_tag %>

Expand All @@ -30,6 +32,8 @@
</head>

<body>
<%%= render "application/analytics/body" %>

<%%= render("application/header") %>
<%%= render("application/flash") %>

Expand Down
3 changes: 3 additions & 0 deletions variants/backend-base/config/app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ default: &default
# The default `From:` address to use for email sent by this application
mail_from: "<%= ENV['MAIL_FROM'] %>"

# this should either begin with GTM- (for a container) or G- (for a tag)
google_analytics_id: "<%= ENV.fetch('GOOGLE_ANALYTICS_ID', nil) %>"

active_record_encryption_primary_key:
"<%= ENV.fetch('ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY') %>"
active_record_encryption_deterministic_key:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,25 @@
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy

Rails.application.config.content_security_policy do |policy|
google_analytics_enabled = Rails.application.config.app.google_analytics_id.present?

# These directives define a quite strict policy by default. You may have to
# loosen this policy as you add elements to the app. Some examples of common
# additions are shown below.
#
policy.default_src :self
policy.font_src :self
policy.img_src :self
policy.img_src :self, :data, *[
*(["*.googletagmanager.com", "*.google-analytics.com"] if google_analytics_enabled)
].compact
policy.object_src :none
policy.script_src :self
policy.script_src :self, *[
*(["*.googletagmanager.com"] if google_analytics_enabled)
].compact
policy.style_src :self
policy.frame_src :self, *[
*(["*.googletagmanager.com"] if google_analytics_enabled)
].compact

# Allow inline-styles
# ###################
Expand Down Expand Up @@ -90,8 +99,11 @@
# * We want to minimize differences in the CSP header between environments so
# that we can find and fix CSP issues in development but enabling the
# webpack-dev-server to communicate over websockets is an exception.
#
policy.connect_src :self, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
policy.connect_src :self, *[
*(["*.googletagmanager.com", "*.google-analytics.com", "*.analytics.google.com"] if google_analytics_enabled),
# required for webpack-dev-server to be used in local development
*(["http://localhost:3035", "ws://localhost:3035"] if Rails.env.development?)
].compact

# Enable CSP reporting
# ####################
Expand Down

0 comments on commit 086c9df

Please sign in to comment.