touchstone 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,6 +1,6 @@
1
- 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](http://thinkvitamin.com/business/marketing/how-to-get-more-customers/).
1
+ 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](http://thinkvitamin.com/business/marketing/how-to-get-more-customers/). I would recommend reading that article to understand what Touchstone does.
2
2
 
3
- Touchstone consists of 3 elements:
3
+ Touchstone consists of 3 classes:
4
4
 
5
5
  ## Campaigns
6
6
  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.
@@ -9,7 +9,12 @@ A campaign records the details of a source from which visitors will sign up to y
9
9
  By adding the parameter ?cid= to each link, the visit will be recorded.
10
10
 
11
11
  ## Campaign Signups
12
- 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.
12
+ 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.
13
+
14
+ ## Prerequisites & Dependencies
15
+ 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.
16
+
17
+ The views are built using Bootstrap so installing Touchstone will introduce dependencies on the sass and sass-bootstrap gems.
13
18
 
14
19
  ## Installation
15
20
  Add the following line to your Gemfile:
@@ -18,13 +23,25 @@ Add the following line to your Gemfile:
18
23
 
19
24
  Then run `bundle install`
20
25
 
21
- Copy the migrations across to your application by running `touchstone:install:migrations`. This will add models for the 3 elements set out above.
26
+ ## Configuration
27
+ Once the gem has been installed run `rails g touchstone`
28
+
29
+ This will:
30
+
31
+ * Copy an initializer file to `config/initializers/touchstone.rb`. You should read this file and set your configuration options before proceeding
32
+ * 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.
33
+ * Mounts the engine in your routes.rb file
34
+
35
+ ## Installation continued
36
+ 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.
37
+
38
+ 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.
22
39
 
23
40
  You will need to mount Touchstone in your application by adding the following line to your `routes.rb` file:
24
41
 
25
42
  mount Touchstone::Engine, :at => "/touchstone/"
26
43
 
27
- Finally, add the following to your `application_controller.rb` file:
44
+ Add the following to your `application_controller.rb` file:
28
45
 
29
46
  before_filter :set_cookie_and_record_visit
30
47
 
@@ -40,6 +57,8 @@ Finally, add the following to your `application_controller.rb` file:
40
57
  end
41
58
 
42
59
  ## Usage
60
+ Restart your server, and if you now visit `http://yourdomain.com/touchstone`, you will see the default page.
61
+
43
62
  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:
44
63
 
45
64
  * Campaigns don't need to be paid campaigns, it can be as simple as a link on your homepage
@@ -62,7 +81,7 @@ The installation steps described above will get you going with tracking visits f
62
81
  end
63
82
  end
64
83
 
65
- 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:
84
+ 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:
66
85
 
67
86
  class User < ActiveRecord::Base
68
87
  ...
@@ -78,8 +97,5 @@ Tracking a user's lifetime value will depend on your transactional logic but ass
78
97
 
79
98
  ## Todo
80
99
 
81
- * Don't constrain Touchstone to an application that only has a Users table. Allow this as a configuration option
82
- * Automatically load routes and application controller content
83
- * Improve design
84
100
  * Add some tests
85
101
  * Allow customisation of currency (only displays dollars at moment although amounts are not stored in a particular currency)
@@ -23,6 +23,7 @@ class Touchstone::CampaignsController < ApplicationController
23
23
 
24
24
  def show
25
25
  @campaign = Campaign.find(params[:id])
26
+ @columns = Touchstone.column_names
26
27
  end
27
28
 
28
29
  def edit
@@ -0,0 +1,21 @@
1
+ module Touchstone
2
+ module CampaignsHelper
3
+
4
+ def signups_table_headers(columns)
5
+ item = ""
6
+ columns.each do |column|
7
+ item += "<th scope='col' id='#{column}'>#{column.humanize}</th>\n"
8
+ end
9
+ item.html_safe
10
+ end
11
+
12
+ def signups_table_content(columns,signup)
13
+ item = ""
14
+ columns.each do |column|
15
+ item += "<td class='#{column}'>#{signup.user.send(column.to_sym)}</td>\n"
16
+ end
17
+ item.html_safe
18
+ end
19
+
20
+ end
21
+ end
@@ -12,7 +12,7 @@ class Campaign < ActiveRecord::Base
12
12
  if self.campaign_signups.length > 0
13
13
  total = Array.new
14
14
  self.campaign_signups.each do |signup|
15
- total << signup.user.lifetime_value # TODO: Fix this
15
+ total << signup.user.lifetime_value
16
16
  end
17
17
  total.inject{|sum,x| sum + x}
18
18
  else
@@ -1,8 +1,8 @@
1
1
  class CampaignSignup < ActiveRecord::Base
2
2
 
3
3
  belongs_to :campaign, :class_name => "Campaign", :foreign_key => "campaign_id"
4
- belongs_to :user, :class_name => "User", :foreign_key => "user_id" # TODO: Fix this
4
+ belongs_to :user, :class_name => Touchstone.association_name.capitalize, :foreign_key => "#{Touchstone.association_name}_id" # TODO: Fix this
5
5
 
6
- attr_accessible :user_id, :campaign_id
6
+ attr_accessible "#{Touchstone.association_name}_id".to_sym, :campaign_id
7
7
 
8
8
  end
@@ -28,19 +28,13 @@
28
28
  <table class="table table-striped">
29
29
  <thead>
30
30
  <tr>
31
- <th scope="col" width="25%">Name</th>
32
- <th scope="col" width="30%">Email</th>
33
- <th scope="col" width="30%">Registered</th>
34
- <th scope="col" width="15%">LTV (inc. VAT)</th>
31
+ <%= signups_table_headers(@columns) %>
35
32
  </tr>
36
33
  </thead>
37
34
  <tbody>
38
35
  <% @campaign.campaign_signups.each do |signup| %>
39
36
  <tr>
40
- <td><%= signup.user.name %></td>
41
- <td><%= signup.user.email %></td>
42
- <td><%= time_ago_in_words(signup.user.created_at) %> ago</td>
43
- <td>$<%= sprintf("%.2f",signup.user.lifetime_value) %></td>
37
+ <%= signups_table_content(@columns,signup)%>
44
38
  </tr>
45
39
  <% end %>
46
40
  </tbody>
@@ -1,8 +1,11 @@
1
1
  class CreateTouchstoneCampaignSignups < ActiveRecord::Migration
2
2
 
3
3
  def change
4
+
5
+ column = Touchstone.association_name + "_id"
6
+
4
7
  create_table :campaign_signups do |t|
5
- t.integer :user_id
8
+ t.integer column.to_sym
6
9
  t.integer :campaign_id
7
10
  t.timestamps
8
11
  end
@@ -0,0 +1,19 @@
1
+ Touchstone.config do |c|
2
+
3
+ # By default, Touchstone assumes that you have a User model
4
+ # in your application and will associate campaign signups
5
+ # with a user_id in the campaign_signups table. You can
6
+ # customise the association by using this configuration
7
+ # option.
8
+
9
+ c.association_name = "User"
10
+
11
+ # When viewing a campaign, Touchstone will show a list of
12
+ # users who have signed up as a result of that campaign.
13
+ # Use this option to set an array of fields that you would
14
+ # like to appear in the view. By default, Touchstone will
15
+ # only show the id and created_at fields.
16
+
17
+ c.column_names = [:id,:created_at]
18
+
19
+ end
@@ -0,0 +1,27 @@
1
+ require 'rails/generators'
2
+
3
+ class TouchstoneGenerator < Rails::Generators::Base
4
+
5
+ def self.source_root
6
+ File.join(File.dirname(__FILE__), 'templates')
7
+ end
8
+
9
+ def copy_initializer_file
10
+ puts "Copying initializer file..."
11
+ copy_file 'touchstone.rb', 'config/initializers/touchstone.rb'
12
+ end
13
+
14
+ def set_before_filter
15
+ puts "Setting before filter in application_controller.rb..."
16
+ insert_into_file 'app/controllers/application_controller.rb', "\n\n\tbefore_filter :set_cookie_and_record_visit", :after => 'ActionController::Base'
17
+ insert_into_file 'app/controllers/application_controller.rb', :before => "end" do
18
+ "\tprivate\n\n\tdef set_cookie_and_record_visit\n\t\tif params[:cid] && Campaign.find_by_id(params[:cid]) && !CampaignVisit.find_by_request_ip(request.remote_ip)\n\t\t\tif !cookies['touchstone_campaign_id']\n\t\t\t\tcookies['touchstone_campaign_id'] = params[:cid]\n\t\t\t\tCampaignVisit.create(:campaign_id => params[:cid], :request_ip => request.remote_ip)\n\t\t\tend\n\t\tend\n\tend\n"
19
+ end
20
+ end
21
+
22
+ def mount_engine
23
+ puts "Mounting engine into routes.rb..."
24
+ insert_into_file 'config/routes.rb', "\n\nmount Touchstone::Engine, :at => '/touchstone/'", :after => 'routes.draw do'
25
+ end
26
+
27
+ end
@@ -1,10 +0,0 @@
1
- # require 'thor'
2
- # include Thor
3
- #
4
- # namespace :touchstone do
5
- #
6
- # desc "Injects the necessary code into your application to run Touchstone"
7
- # task :install do
8
- # inject_into_file "#{Rails.root}/config/routes.rb", "mount Touchstone::Engine, :at => '/touchstone/'", :after => "routes.draw do"
9
- # end
10
- # end
@@ -4,15 +4,23 @@ module Touchstone
4
4
 
5
5
  extend self
6
6
 
7
- attr_accessor :association_name
7
+ attr_accessor :association_name, :column_names
8
8
 
9
9
  def association_name=name
10
- @name = name
10
+ @name = name.downcase
11
11
  end
12
12
 
13
13
  def association_name
14
14
  @name || "user"
15
15
  end
16
16
 
17
+ def column_names=columns
18
+ @columns = columns.map(&:to_s)
19
+ end
20
+
21
+ def column_names
22
+ @columns || [:id,:created_at]
23
+ end
24
+
17
25
  end
18
26
  end
@@ -1,3 +1,3 @@
1
1
  module Touchstone
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/touchstone.rb CHANGED
@@ -5,12 +5,20 @@ module Touchstone
5
5
 
6
6
  include Configuration
7
7
 
8
- mattr_accessor :app_root
9
-
10
8
  class << self
11
- def configure &block
9
+
10
+ def config &block
12
11
  yield Touchstone::Configuration
13
12
  end
13
+
14
+ def association_name
15
+ Touchstone::Configuration.association_name
16
+ end
17
+
18
+ def column_names
19
+ Touchstone::Configuration.column_names
20
+ end
21
+
14
22
  end
15
23
 
16
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: touchstone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-14 00:00:00.000000000 Z
12
+ date: 2012-05-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -89,6 +89,7 @@ files:
89
89
  - app/controllers/touchstone/application_controller.rb
90
90
  - app/controllers/touchstone/campaigns_controller.rb
91
91
  - app/helpers/touchstone/application_helper.rb
92
+ - app/helpers/touchstone/campaigns_helper.rb
92
93
  - app/models/campaign.rb
93
94
  - app/models/campaign_signup.rb
94
95
  - app/models/campaign_visit.rb
@@ -103,6 +104,8 @@ files:
103
104
  - db/migrate/001_create_touchstone_campaigns.rb
104
105
  - db/migrate/002_create_touchstone_campaign_signups.rb
105
106
  - db/migrate/003_create_touchstone_campaign_visits.rb
107
+ - lib/generators/touchstone/templates/touchstone.rb
108
+ - lib/generators/touchstone/touchstone_generator.rb
106
109
  - lib/tasks/touchstone_tasks.rake
107
110
  - lib/touchstone/configuration.rb
108
111
  - lib/touchstone/engine.rb
@@ -156,7 +159,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
156
159
  version: '0'
157
160
  segments:
158
161
  - 0
159
- hash: 2775789728872251427
162
+ hash: -3745211063638779755
160
163
  required_rubygems_version: !ruby/object:Gem::Requirement
161
164
  none: false
162
165
  requirements:
@@ -165,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
168
  version: '0'
166
169
  segments:
167
170
  - 0
168
- hash: 2775789728872251427
171
+ hash: -3745211063638779755
169
172
  requirements: []
170
173
  rubyforge_project:
171
174
  rubygems_version: 1.8.20