├── .rspec ├── gems.rb ├── lib ├── gtm_rails │ ├── version.rb │ ├── config.rb │ ├── railtie.rb │ ├── hooks.rb │ ├── yaml_loader.rb │ └── helper.rb └── gtm_rails.rb ├── gemfiles ├── Gemfile-rails4.1.x ├── Gemfile-rails4.2.x ├── Gemfile-rails5.0.x ├── Gemfile-rails5.1.x ├── Gemfile-rails5.2.x └── Gemfile-rails_edge ├── Rakefile ├── spec ├── config │ └── google_tag_manager.yml ├── gtm_rails │ └── helper_spec.rb └── spec_helper.rb ├── CHANGELOG.md ├── gtm_rails.gemspec ├── LICENSE ├── .travis.yml └── README.md /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | --warnings 4 | -------------------------------------------------------------------------------- /gems.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | -------------------------------------------------------------------------------- /lib/gtm_rails/version.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | module GtmRails 4 | VERSION = '0.5.0' 5 | end 6 | -------------------------------------------------------------------------------- /gemfiles/Gemfile-rails4.1.x: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails', '~> 4.1.0' 4 | gem 'sqlite3' 5 | 6 | gemspec path: '../' 7 | -------------------------------------------------------------------------------- /gemfiles/Gemfile-rails4.2.x: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails', '~> 4.2.0' 4 | gem 'sqlite3' 5 | 6 | gemspec path: '../' 7 | -------------------------------------------------------------------------------- /gemfiles/Gemfile-rails5.0.x: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails', '~> 5.0.0' 4 | gem 'sqlite3' 5 | 6 | gemspec path: '../' 7 | -------------------------------------------------------------------------------- /gemfiles/Gemfile-rails5.1.x: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails', '~> 5.1.0' 4 | gem 'sqlite3' 5 | 6 | gemspec path: '../' 7 | -------------------------------------------------------------------------------- /gemfiles/Gemfile-rails5.2.x: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails', '~> 5.2.0' 4 | gem 'sqlite3' 5 | 6 | gemspec path: '../' 7 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/gem_tasks' 4 | require 'rspec/core/rake_task' 5 | 6 | RSpec::Core::RakeTask.new(:spec) 7 | 8 | task default: :spec 9 | -------------------------------------------------------------------------------- /lib/gtm_rails.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | require 'gtm_rails/version' 4 | require 'gtm_rails/config' 5 | require 'gtm_rails/helper' 6 | require 'gtm_rails/hooks' 7 | require 'gtm_rails/railtie' 8 | -------------------------------------------------------------------------------- /spec/config/google_tag_manager.yml: -------------------------------------------------------------------------------- 1 | test: 2 | foo: GTM-XXXX 3 | bar: GTM-YYYY 4 | baz: 5 | development: 6 | foo: GTM-XXYY 7 | bar: GTM-YYZZ 8 | production: 9 | foo: GTM-XXZZ 10 | bar: GTM-ZZZZ 11 | -------------------------------------------------------------------------------- /lib/gtm_rails/config.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | require 'singleton' 4 | 5 | module GtmRails 6 | class Config 7 | include ActiveSupport::Configurable 8 | 9 | config_accessor :container_ids 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /gemfiles/Gemfile-rails_edge: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | git_source(:github) {|repo| "https://github.com/#{repo}.git" } 4 | 5 | gem 'arel', github: 'rails/arel' 6 | gem 'rails', github: 'rails/rails' 7 | gem 'sqlite3' 8 | 9 | gemspec path: '../' 10 | -------------------------------------------------------------------------------- /lib/gtm_rails/railtie.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | module GtmRails 4 | class Railtie < ::Rails::Railtie 5 | initializer 'gtm_rails.initialize' do 6 | ActiveSupport.on_load(:action_view) do 7 | GtmRails::Hooks.init 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/gtm_rails/hooks.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | module GtmRails 4 | class Hooks 5 | def self.init 6 | require 'gtm_rails/yaml_loader' 7 | 8 | loader = ::GtmRails::YamlLoader.new 9 | 10 | GtmRails::Config.configure do |config| 11 | config.container_ids = (loader.load[Rails.env] || {}).with_indifferent_access 12 | end 13 | 14 | ActionView::Base.send :include, GtmRails::Helper 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.5.0 (2017-04-27) 2 | 3 | - Fix JavaScript-escaped bug 4 | 5 | ## 0.4.0 (2017-04-22) 6 | 7 | - Remove `google_tag_manager` method. Use `google_tag_manager_script_tag` and `google_tag_manager_noscript_tag` instead of `google_tag_manager`. 8 | 9 | ## 0.3.1 (2017-01-31) 10 | 11 | - `google_tag_manager` is obsoleted method. 12 | 13 | ## 0.3.0 (2017-01-26) 14 | 15 | - Added ability to set script tag and noscript tag individually. 16 | 17 | ## 0.2.1 (2017-01-26) 18 | 19 | - Fix bug: Use `Rails.env` instead of `ENV['RAILS_ENV']` 20 | 21 | ## 0.2.0 (2017-01-26) 22 | 23 | - __BREAKING CHANGE__ Refine config/google_tag_manager.yml format 24 | - Support Rails 4.1.x 25 | 26 | ## 0.1.2 (2017-01-25) 27 | 28 | - Loose conditions for RAILS_ENV. 29 | 30 | ## 0.1.1 (2017-01-25) 31 | 32 | - Bug fix. 33 | 34 | ## 0.1.0 (2017-01-25) 35 | 36 | - The first release. 37 | -------------------------------------------------------------------------------- /lib/gtm_rails/yaml_loader.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | module GtmRails 4 | class YamlLoader 5 | def load 6 | yaml = Rails.root.join('config', 'google_tag_manager.yml') 7 | 8 | config = if yaml && yaml.exist? 9 | require 'yaml' 10 | require 'erb' 11 | YAML.load(ERB.new(yaml.read).result) || {} 12 | else 13 | raise 'Could not load database configuration. No such file - config/google_tag_manager.yml' 14 | end 15 | 16 | config 17 | rescue Psych::SyntaxError => e 18 | raise "YAML syntax error occurred while parsing config/google_tag_manager.yml. " \ 19 | "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ 20 | "Error: #{e.message}" 21 | rescue => e 22 | raise e, "Cannot load `GtmRails:YamlLoader.load`:\n#{e.message}", e.backtrace 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /gtm_rails.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | $:.push File.expand_path('../lib', __FILE__) 4 | 5 | require 'gtm_rails/version' 6 | 7 | Gem::Specification.new do |s| 8 | s.platform = Gem::Platform::RUBY 9 | s.name = 'gtm_rails' 10 | s.summary = 'Simply embed Google Tag Manager container snippet into Rails application' 11 | s.description = 'Simply embed Google Tag Manager container snippet into Rails application' 12 | 13 | s.version = GtmRails::VERSION 14 | 15 | s.license = 'MIT' 16 | 17 | s.authors = ['Koichi ITO'] 18 | s.email = 'koic.ito@gmail.com' 19 | s.homepage = 'http://github.com/koic/gtm_rails' 20 | 21 | s.files = Dir[ 22 | 'README.md', 23 | 'lib/**/*', 24 | 'LICENSE' 25 | ] 26 | s.require_paths = ['lib'] 27 | 28 | s.required_ruby_version = '>= 2.2.2' 29 | 30 | s.add_dependency('rails', '>= 4.1.0') 31 | 32 | s.add_development_dependency('rspec-rails', '>= 3.0.0') 33 | s.add_development_dependency('sqlite3') 34 | end 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Koichi ITO 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | sudo: false 3 | 4 | rvm: 5 | - 2.2.10 6 | - 2.3.8 7 | - 2.4.5 8 | - 2.5.3 9 | - ruby-head 10 | 11 | before_install: 12 | - travis_retry gem update --system || travis_retry gem update --system 2.7.8 13 | - travis_retry gem install bundler --no-document || travis_retry gem install bundler --no-document -v 1.17.3 14 | 15 | gemfile: 16 | - gemfiles/Gemfile-rails4.1.x 17 | - gemfiles/Gemfile-rails4.2.x 18 | - gemfiles/Gemfile-rails5.0.x 19 | - gemfiles/Gemfile-rails5.1.x 20 | - gemfiles/Gemfile-rails5.2.x 21 | - gemfiles/Gemfile-rails_edge 22 | 23 | matrix: 24 | allow_failures: 25 | - rvm: 2.4.5 26 | gemfile: gemfiles/Gemfile-rails_edge 27 | - rvm: 2.5.3 28 | gemfile: gemfiles/Gemfile-rails_edge 29 | - rvm: ruby-head 30 | gemfile: gemfiles/Gemfile-rails4.1.x 31 | - rvm: ruby-head 32 | gemfile: gemfiles/Gemfile-rails4.2.x 33 | - rvm: ruby-head 34 | gemfile: gemfiles/Gemfile-rails5.0.x 35 | - rvm: ruby-head 36 | gemfile: gemfiles/Gemfile-rails5.1.x 37 | - rvm: ruby-head 38 | gemfile: gemfiles/Gemfile-rails5.2.x 39 | - rvm: ruby-head 40 | gemfile: gemfiles/Gemfile-rails_edge 41 | exclude: 42 | - rvm: 2.2.10 43 | gemfile: gemfiles/Gemfile-rails_edge 44 | - rvm: 2.3.8 45 | gemfile: gemfiles/Gemfile-rails_edge 46 | -------------------------------------------------------------------------------- /lib/gtm_rails/helper.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | module GtmRails 4 | module Helper 5 | # 6 | # Use this method as close to the opening tag as possible on every page of your website. 7 | # 8 | def google_tag_manager_script_tag(label) 9 | container_id = GtmRails::Config.container_ids[label] 10 | 11 | return '' if container_id.blank? 12 | 13 | <<-HTML.strip_heredoc.html_safe 14 | 15 | 20 | 21 | HTML 22 | end 23 | 24 | # 25 | # Use this method immediately after the opening tag on every page of your website. 26 | # 27 | def google_tag_manager_noscript_tag(label) 28 | container_id = GtmRails::Config.container_ids[label] 29 | 30 | return '' if container_id.blank? 31 | 32 | <<-HTML.strip_heredoc.html_safe 33 | 34 | 36 | 37 | HTML 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/gtm_rails/helper_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | describe GtmRails::Helper, type: :helper do 4 | before do 5 | allow(Rails).to receive(:root) { Pathname('spec') } 6 | 7 | GtmRails::Hooks.init 8 | end 9 | 10 | let(:container_id) { 'GTM-XXXX' } 11 | 12 | describe '#google_tag_manager_script_tag' do 13 | subject { helper.google_tag_manager_script_tag(gtm_key) } 14 | 15 | context 'container id is set' do 16 | let(:gtm_key) { :foo } 17 | 18 | it { is_expected.to eq <<-EOS.strip_heredoc } 19 | 20 | 25 | 26 | EOS 27 | end 28 | 29 | context 'container id is not set' do 30 | let(:gtm_key) { :baz } 31 | 32 | it { is_expected.to eq '' } 33 | end 34 | end 35 | 36 | describe '#google_tag_manager_noscript_tag' do 37 | subject { helper.google_tag_manager_noscript_tag(gtm_key) } 38 | 39 | context 'container id is set' do 40 | let(:gtm_key) { :foo } 41 | 42 | it { is_expected.to eq <<-EOS.strip_heredoc } 43 | 44 | 46 | 47 | EOS 48 | end 49 | 50 | context 'container id is not set' do 51 | let(:gtm_key) { :baz } 52 | 53 | it { is_expected.to eq '' } 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gtm_rails [![Build Status](https://travis-ci.org/koic/gtm_rails.svg)](https://travis-ci.org/koic/gtm_rails) [![Gem Version](https://badge.fury.io/rb/gtm_rails.svg)](http://badge.fury.io/rb/gtm_rails) [![git.legal](https://git.legal/projects/3929/badge.svg "Number of libraries approved")](https://git.legal/projects/3929) 2 | 3 | Simply embed Google Tag Manager container snippet into Rails application. 4 | 5 | ## Installation 6 | 7 | Add these lines to your application's Gemfile: 8 | 9 | ``` 10 | gem 'gtm_rails' 11 | ``` 12 | 13 | And then execute: 14 | 15 | ``` 16 | $ bundle install 17 | ``` 18 | 19 | ## Configuration 20 | 21 | Create `config/google_tag_manager.yml` in your Rails application. 22 | 23 | ```yaml 24 | staging: 25 | foo: GTM-YourGtmId1 26 | bar: GTM-YourGtmId2 27 | baz: GTM-YourGtmId3 28 | production: 29 | foo: GTM-YourGtmId4 30 | bar: GTM-YourGtmId5 31 | baz: GTM-YourGtmId6 32 | ``` 33 | 34 | The above is a sample. `foo`, `bar`, `baz` are arbitrary label names, and replacing GTM-XXXX with your container ID. 35 | 36 | In view, use two helper methods. 37 | 38 | 1. `google_tag_manager_script_tag(label_name)` 39 | 2. `google_tag_manager_noscript_tag(label_name)` 40 | 41 | These method arguments are a label name specified in `config/google_tag_manager.yml`. 42 | 43 | First, following method as close to the opening `` tag as possible on every page of your website. 44 | 45 | ```erb 46 | <%= google_tag_manager_script_tag(:foo) %> 47 | ``` 48 | 49 | Google Tag Manager container snippet will be expanded based on `Rails.env` and label name. If there is no match, a blank string is returned. 50 | 51 | ```html 52 | 53 | 58 | 59 | ``` 60 | 61 | Second, following method immediately after the opening `` tag on every page of your website. 62 | 63 | ```erb 64 | <%= google_tag_manager_noscript_tag(:foo) %> 65 | ``` 66 | 67 | Google Tag Manager container snippet will be expanded based on `Rails.env` and label name. If there is no match, a blank string is returned. 68 | 69 | ```html 70 | 71 | 73 | 74 | ``` 75 | 76 | For more detailed GTM please click here to [read more](https://developers.google.com/tag-manager/quickstart). 77 | 78 | ## Contributing 79 | 80 | 1. Fork it 81 | 2. Create your feature branch (`git checkout -b my-new-feature`) 82 | 3. Commit your changes (`git commit -am 'Add some feature'`) 83 | 4. Push to the branch (`git push origin my-new-feature`) 84 | 5. Create new Pull Request 85 | 86 | ## License 87 | 88 | gtm_rails is released under the [MIT License](http://www.opensource.org/licenses/MIT). 89 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen-string-literal: true 2 | 3 | # This file was generated by the `rspec --init` command. Conventionally, all 4 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 5 | # The generated `.rspec` file contains `--require spec_helper` which will cause 6 | # this file to always be loaded, without a need to explicitly require it in any 7 | # files. 8 | # 9 | # Given that it is always loaded, you are encouraged to keep this file as 10 | # light-weight as possible. Requiring heavyweight dependencies from this file 11 | # will add to the boot time of your test suite on EVERY test run, even for an 12 | # individual file that may not need all of that loaded. Instead, consider making 13 | # a separate helper file that requires the additional dependencies and performs 14 | # the additional setup, and require it from the spec files that actually need 15 | # it. 16 | # 17 | # The `.rspec` file also contains a few flags that are not defaults but that 18 | # users commonly want. 19 | # 20 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 21 | 22 | ENV['RAILS_ENV'] = 'test' 23 | 24 | require 'rails/all' 25 | require 'rspec/rails' 26 | require 'gtm_rails' 27 | require 'action_view/railtie' 28 | 29 | ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') 30 | 31 | RSpec.configure do |config| 32 | # rspec-expectations config goes here. You can use an alternate 33 | # assertion/expectation library such as wrong or the stdlib/minitest 34 | # assertions if you prefer. 35 | config.expect_with :rspec do |expectations| 36 | # This option will default to `true` in RSpec 4. It makes the `description` 37 | # and `failure_message` of custom matchers include text for helper methods 38 | # defined using `chain`, e.g.: 39 | # be_bigger_than(2).and_smaller_than(4).description 40 | # # => "be bigger than 2 and smaller than 4" 41 | # ...rather than: 42 | # # => "be bigger than 2" 43 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 44 | end 45 | 46 | # rspec-mocks config goes here. You can use an alternate test double 47 | # library (such as bogus or mocha) by changing the `mock_with` option here. 48 | config.mock_with :rspec do |mocks| 49 | # Prevents you from mocking or stubbing a method that does not exist on 50 | # a real object. This is generally recommended, and will default to 51 | # `true` in RSpec 4. 52 | mocks.verify_partial_doubles = true 53 | end 54 | 55 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will 56 | # have no way to turn it off -- the option exists only for backwards 57 | # compatibility in RSpec 3). It causes shared context metadata to be 58 | # inherited by the metadata hash of host groups and examples, rather than 59 | # triggering implicit auto-inclusion in groups with matching metadata. 60 | config.shared_context_metadata_behavior = :apply_to_host_groups 61 | 62 | # The settings below are suggested to provide a good initial experience 63 | # with RSpec, but feel free to customize to your heart's content. 64 | =begin 65 | # This allows you to limit a spec run to individual examples or groups 66 | # you care about by tagging them with `:focus` metadata. When nothing 67 | # is tagged with `:focus`, all examples get run. RSpec also provides 68 | # aliases for `it`, `describe`, and `context` that include `:focus` 69 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively. 70 | config.filter_run_when_matching :focus 71 | 72 | # Allows RSpec to persist some state between runs in order to support 73 | # the `--only-failures` and `--next-failure` CLI options. We recommend 74 | # you configure your source control system to ignore this file. 75 | config.example_status_persistence_file_path = "spec/examples.txt" 76 | 77 | # Limits the available syntax to the non-monkey patched syntax that is 78 | # recommended. For more details, see: 79 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 80 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 81 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 82 | config.disable_monkey_patching! 83 | 84 | # This setting enables warnings. It's recommended, but in some cases may 85 | # be too noisy due to issues in dependencies. 86 | config.warnings = true 87 | 88 | # Many RSpec users commonly either run the entire suite or an individual 89 | # file, and it's useful to allow more verbose output when running an 90 | # individual spec file. 91 | if config.files_to_run.one? 92 | # Use the documentation formatter for detailed output, 93 | # unless a formatter has already been configured 94 | # (e.g. via a command-line flag). 95 | config.default_formatter = 'doc' 96 | end 97 | 98 | # Print the 10 slowest examples and example groups at the 99 | # end of the spec run, to help surface which specs are running 100 | # particularly slow. 101 | config.profile_examples = 10 102 | 103 | # Run specs in random order to surface order dependencies. If you find an 104 | # order dependency and want to debug it, you can fix the order by providing 105 | # the seed, which is printed after each run. 106 | # --seed 1234 107 | config.order = :random 108 | 109 | # Seed global randomization in this process using the `--seed` CLI option. 110 | # Setting this allows you to use `--seed` to deterministically reproduce 111 | # test failures related to randomization by passing the same `--seed` value 112 | # as the one that triggered the failure. 113 | Kernel.srand config.seed 114 | =end 115 | end 116 | --------------------------------------------------------------------------------