diff --git a/lib/rack/tracker.rb b/lib/rack/tracker.rb index a7e1780..640d971 100644 --- a/lib/rack/tracker.rb +++ b/lib/rack/tracker.rb @@ -58,12 +58,7 @@ def html?; @headers['Content-Type'] =~ /html/; end def inject(env, response) @handlers.each(env) do |handler| - # Sub! is enough, in well formed html there's only one head or body tag. - # Block syntax need to be used, otherwise backslashes in input will mess the output. - # @see http://stackoverflow.com/a/4149087/518204 and https://github.com/railslove/rack-tracker/issues/50 - response.sub! %r{#{handler.position}>} do |m| - handler.render << m.to_s - end + handler.inject(response) end response end diff --git a/lib/rack/tracker/google_tag_manager/google_tag_manager.rb b/lib/rack/tracker/google_tag_manager/google_tag_manager.rb index 4bac22c..06d0c08 100644 --- a/lib/rack/tracker/google_tag_manager/google_tag_manager.rb +++ b/lib/rack/tracker/google_tag_manager/google_tag_manager.rb @@ -6,16 +6,29 @@ def write end end - # It is strongly recommended to put the google_tag_manager snippet only in the body tag - # https://developers.google.com/tag-manager/quickstart - self.position = :body + def inject(response) + # Sub! is enough, in well formed html there's only one head or body tag. + # Block syntax need to be used, otherwise backslashes in input will mess the output. + # @see http://stackoverflow.com/a/4149087/518204 and https://github.com/railslove/rack-tracker/issues/50 + response.sub! %r{
} do |m| + m.to_s << self.render_head + end + response.sub! %r{} do |m| + m.to_s << self.render_body + end + response + end def container options[:container].respond_to?(:call) ? options[:container].call(env) : options[:container] end - def render - Tilt.new( File.join( File.dirname(__FILE__), 'template', 'google_tag_manager.erb') ).render(self) + def render_head + Tilt.new( File.join( File.dirname(__FILE__), 'template', 'google_tag_manager_head.erb') ).render(self) + end + + def render_body + Tilt.new( File.join( File.dirname(__FILE__), 'template', 'google_tag_manager_body.erb') ).render(self) end def self.track(name, *event) diff --git a/lib/rack/tracker/google_tag_manager/template/google_tag_manager_body.erb b/lib/rack/tracker/google_tag_manager/template/google_tag_manager_body.erb new file mode 100644 index 0000000..cc30f77 --- /dev/null +++ b/lib/rack/tracker/google_tag_manager/template/google_tag_manager_body.erb @@ -0,0 +1,4 @@ +<% if container %> + +<% end %> diff --git a/lib/rack/tracker/google_tag_manager/template/google_tag_manager.erb b/lib/rack/tracker/google_tag_manager/template/google_tag_manager_head.erb similarity index 64% rename from lib/rack/tracker/google_tag_manager/template/google_tag_manager.erb rename to lib/rack/tracker/google_tag_manager/template/google_tag_manager_head.erb index 9a3743f..f096851 100644 --- a/lib/rack/tracker/google_tag_manager/template/google_tag_manager.erb +++ b/lib/rack/tracker/google_tag_manager/template/google_tag_manager_head.erb @@ -9,12 +9,9 @@ dataLayer.push( ); - - <% end %> diff --git a/lib/rack/tracker/handler.rb b/lib/rack/tracker/handler.rb index cab471d..cf78dcc 100644 --- a/lib/rack/tracker/handler.rb +++ b/lib/rack/tracker/handler.rb @@ -23,6 +23,16 @@ def render raise NotImplementedError.new('needs implementation') end + def inject(response) + # Sub! is enough, in well formed html there's only one head or body tag. + # Block syntax need to be used, otherwise backslashes in input will mess the output. + # @see http://stackoverflow.com/a/4149087/518204 and https://github.com/railslove/rack-tracker/issues/50 + response.sub! %r{#{self.position}>} do |m| + self.render << m.to_s + end + response + end + def self.track(name, event) raise NotImplementedError.new("class method `#{__callee__}` is not implemented.") end diff --git a/spec/handler/google_tag_manager_spec.rb b/spec/handler/google_tag_manager_spec.rb index 3edaa14..ed1e147 100644 --- a/spec/handler/google_tag_manager_spec.rb +++ b/spec/handler/google_tag_manager_spec.rb @@ -7,12 +7,6 @@ def env } end - it 'will be placed in the body by default' do - expect(described_class.position).to eq(:body) - expect(described_class.new(env).position).to eq(:body) - expect(described_class.new(env, position: :head).position).to eq(:head) - end - describe "with events" do describe "default" do def env @@ -23,7 +17,7 @@ def env }} end - subject { described_class.new(env, container: 'somebody').render } + subject { described_class.new(env, container: 'somebody').render_head } it "will show events" do expect(subject).to match(%r{"page":"Cart","price":50,"content_ids":\["sku_1","sku_2","sku_3"\]}) end @@ -31,7 +25,7 @@ def env end describe "with dynamic tracker" do - subject { described_class.new(env, { container: lambda { |env| return env[:misc] }}).render } + subject { described_class.new(env, { container: lambda { |env| return env[:misc] }}).render_head } it 'will call tracker lambdas to obtain tracking codes' do expect(subject).to match(%r{\(window,document,'script','dataLayer','foobar'\)}) diff --git a/spec/integration/google_tag_manager_integration_spec.rb b/spec/integration/google_tag_manager_integration_spec.rb index e7c66e6..8bc6345 100644 --- a/spec/integration/google_tag_manager_integration_spec.rb +++ b/spec/integration/google_tag_manager_integration_spec.rb @@ -11,8 +11,9 @@ subject { page } it "embeds the script tag with tracking event from the controller action" do - expect(page.find("body")).to have_content 'GTM-ABCDEF' - expect(page.find("body")).to have_content "dataLayer.push( {\"click\":\"X\",\"price\":10}, {\"transactionProducts\":[{\"sku\":\"DD44\",\"name\":\"T-shirt\"},{\"sku\":\"DD66\",\"name\":\"Jeans\"}]} );" + expect(page.find("head")).to have_content 'GTM-ABCDEF' + expect(page.find("head")).to have_content "dataLayer.push( {\"click\":\"X\",\"price\":10}, {\"transactionProducts\":[{\"sku\":\"DD44\",\"name\":\"T-shirt\"},{\"sku\":\"DD66\",\"name\":\"Jeans\"}]} );" + expect(page.find("body")).to have_xpath '//body/noscript/iframe[@src="https://www.googletagmanager.com/ns.html?id=GTM-ABCDEF"]' end end \ No newline at end of file