Skip to content
This repository

Touchstone is a Rails Engine that adds the ability to track advanced metrics for your web app.

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 app
Octocat-spinner-32 config
Octocat-spinner-32 db
Octocat-spinner-32 lib
Octocat-spinner-32 script
Octocat-spinner-32 test
Octocat-spinner-32 .gitignore
Octocat-spinner-32 CHANGELOG.markdown
Octocat-spinner-32 Gemfile
Octocat-spinner-32 Gemfile.lock
Octocat-spinner-32 MIT-LICENSE
Octocat-spinner-32 README.markdown
Octocat-spinner-32 Rakefile
Octocat-spinner-32 touchstone.gemspec
README.markdown

Touchstone is a Rails Engine that adds the ability to track advanced metrics for your web app. It is inspired by this post on the Think Vitamin blog. I would recommend reading that article to understand what Touchstone does.

Please consider this an alpha release. Versions will be released fairly quickly. Hopefully nothing will break but I'm trying to get this running in production on one of my apps so correcting errors as I go.

Touchstone consists of 3 classes:

Campaigns

A campaign records the details of a source from which visitors will sign up to your website. It can be a Google Adwords campaign or a link on your homepage.

Campaign Visits

By adding the parameter ?cid= to each link, the visit will be recorded.

Campaign Signups

When a visitor visits your website via a link containing ?cid= and then signs up, the sign up is tied back to that visit and that campaign. You can then track the revenue obtained from each visitor against the cost of a particular campaign.

Prerequisites & Dependencies

Touchstone requires your application to have something like a User model. The model doesn't need to be called User (you can configure this) but the purpose of Touchstone is to track users who signup to your application in response to a campaign.

The views are built using Bootstrap so installing Touchstone will introduce dependencies on the sass and sass-bootstrap gems.

Installation

Add the following line to your Gemfile:

gem 'touchstone'

Then run bundle install

Configuration

Once the gem has been installed run rails g touchstone

This will:

  • Copy an initializer file to config/initializers/touchstone.rb. You should read this file and set your configuration options before proceeding
  • Add a before filter to your application controller. NB: This defaults to setting a private method for the filter. If you already have private defined in your application controller, you will need to remove the duplicate declaration. Not currently working. You will need to update application_controller.rb manually. See below.
  • Mounts the engine in your routes.rb file

Authentication

By default, Touchstone will require http_basic authentication to access. The credentials for access will be read from a YAML file called touchstone.yml in your config folder. You will need to create this file unless you choose not to restrict access to Touchstone (not recommended).

Installation continued

Copy the migrations across to your application by running rake touchstone:install:migrations. This will add migrations to create the tables for the 3 classes set out above.

If, for any reason the command rails g touchstone has not made the correct changes to your files, these are the changes that need to be made and can be made manually. If you do not have a User model, the configuration option association_name in the Touchstone initializer must be set before running the Touchstone migrations.

You will need to mount Touchstone in your application by adding the following line to your routes.rb file:

mount Touchstone::Engine, :at => "/touchstone/"

Add the following to your application_controller.rb file:

before_filter :set_cookie_and_record_visit

private

def set_cookie_and_record_visit
    if params[:cid] && Campaign.find_by_id(params[:cid]) && !CampaignVisit.find_by_request_ip(request.remote_ip)
        if !cookies['touchstone_campaign_id']
            cookies['touchstone_campaign_id'] = "#{params[:cid]}"
            CampaignVisit.create(:campaign_id => params[:cid], :request_ip => request.remote_ip)
        end
    end
end

Usage

Restart your server, and if you now visit http://yourdomain.com/touchstone, you will see the default page.

Usage is very simple. Assume you are running a Google Adwords campaign for 1 week at a cost of $100. Create this campaign in Touchstone and it will return a campaign ID. Make sure all your links on Adwords contain the parameter at the end ?cid={campaign_id} where campaign_id is the id generated by Touchstone. Please note:

  • Campaigns don't need to be paid campaigns, it can be as simple as a link on your homepage
  • You can update the campaign cost at any time. All calculations are "on the fly" so you're metrics will update automatically

The installation steps described above will get you going with tracking visits from particular campaigns but you still have some work to do in linking this to your users. Touchstone only really provides a benefit when you track how much revenue your users bring in and then it will compare that to the cost of your campaigns. By way of examples only, you could adopt the following pattern to record a campaign signup:

class UsersController < ApplicationController
    ...
    def create
        @user = User.new(params[:user])
        if @user.save
            unless cookies['touchstone_campaign_id'].nil?
                campaign_id = cookies['touchstone_campaign_id']
                CampaignSignup.create(:user_id => @user.id, :campaign_id => campaign_id)
            end
            flash["notice"] = "Successfully signed up"
            ...
        end
    end
end

Touchstone requires your user model to have a method called lifetime_value in order to calculate the revenue that a user has generated. Tracking a user's lifetime value will depend on your transactional logic but assuming a common pattern of a user having a subscription and that subscription containing many transactions, the following could be used:

class User < ActiveRecord::Base
    ...
    def lifetime_value
        total = Array.new
        self.subscription.transactions.each do |t|
            total << t.amount
        end
        total.inject{|sum,x| sum + x}
    end
    ...
end

Todo

  • Add some tests
  • Copy css and js to application
Something went wrong with that request. Please try again.