ahoy_matey 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7973efa4435f37d54dfa0bd84b7441473a4e3ddf
4
- data.tar.gz: 3ceb16b3595ae8b258e63102ae996667652802af
3
+ metadata.gz: 443dfa85abf63a4f515ea9c6865beb09f77404ab
4
+ data.tar.gz: 9099a3d7a51f6426f0ebae09fd3d9c831385a1e5
5
5
  SHA512:
6
- metadata.gz: a16bd0b6d30f134a901d2574bc944d411e049e1a7fcaae46707245a98287013b2e4c26c69eca8fd77cf00394e34bd6576843b62d85fc7d93e92344565e7e58a1
7
- data.tar.gz: 6c228da084f4949c9fbd8618b1fdc2a04f83a75402d3f2eadbba954f6f02988b040b223181f4b7a34e5ec6d5e375c218a367ceb3457239966bff877b8b564503
6
+ metadata.gz: a0967ab9bfbb9fe5a22214d1eb74705edbeede65bdb82a07ecf2982e49a8ce8c74bd22ddfe2b302e16d63d602b1d5058c30322d1b5011879f3fc407dee9e1b37
7
+ data.tar.gz: b1c10a691345e7078f017eb009b64f17106cb1324bac5432bd85cc4986a18016028c4a917fe58d8e1e664ab958db43989b0097e36666343755c2001c65df199d
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  :fire: Simple, powerful visit tracking for Rails
4
4
 
5
- In under a minute, start learning more about your visitors.
5
+ You get:
6
6
 
7
7
  - traffic source - referrer, referring domain, landing page, search keyword
8
8
  - location - country, region, and city
@@ -39,25 +39,49 @@ Lastly, include the javascript file in `app/assets/javascripts/application.js` a
39
39
  //= require ahoy
40
40
  ```
41
41
 
42
- ## What You Get
42
+ ## How It Works
43
43
 
44
- When a person visits your website, Ahoy creates a visit with lots of useful information.
44
+ When someone visits your website, Ahoy creates a visit with lots of useful information.
45
45
 
46
46
  Use the `current_visit` method to access it.
47
47
 
48
- The information is great on it’s own, but super powerful when combined with other models.
48
+ Explore your visits with queries like:
49
49
 
50
- You can store the visit id on any model. For instance, when someone places an order:
50
+ ```ruby
51
+ Visit.group(:search_keyword).count
52
+ Visit.group(:country).count
53
+ Visit.group(:referring_domain).count
54
+ ```
55
+
56
+ [Chartkick](http://chartkick.com/) and [Groupdate](https://github.com/ankane/groupdate) make it super easy to visualize the data.
57
+
58
+ ```erb
59
+ <%= line_chart Visit.group_by_day(:created_at).count %>
60
+ ```
61
+
62
+ ## The Power
63
+
64
+ This information is great on its own, but super powerful when combined with other models.
65
+
66
+ Let’s associate orders with visits.
51
67
 
52
68
  ```ruby
53
69
  class Order < ActiveRecord::Base
54
- visitable # needs better name
70
+ visitable
55
71
  end
56
72
  ```
57
73
 
58
- The visit_id column will be automatically set. Magic!
74
+ When a visitor places an order, the `visit_id` column will be automatically set. Magic!
59
75
 
60
- When you want to explore where most orders are coming from, you can do a number of queries.
76
+ To see where most of your orders are coming from, create an association:
77
+
78
+ ```ruby
79
+ class Order < ActiveRecord::Base
80
+ belongs_to :visit
81
+ end
82
+ ```
83
+
84
+ And query away:
61
85
 
62
86
  ```ruby
63
87
  Order.joins(:visit).group("referring_domain").count
@@ -65,18 +89,52 @@ Order.joins(:visit).group("device_type").count
65
89
  Order.joins(:visit).group("city").count
66
90
  ```
67
91
 
92
+ ## Users
93
+
94
+ Ahoy automatically attaches the `current_user` to the `current_visit`.
95
+
96
+ With [Devise](https://github.com/plataformatec/devise), it will attach the user even if he / she signs in after the visit starts.
97
+
98
+ To see the visits for a given user, create an association:
99
+
100
+ ```ruby
101
+ class User < ActiveRecord::Base
102
+ has_many :visits
103
+ end
104
+ ```
105
+
106
+ And use:
107
+
108
+ ```ruby
109
+ user = User.first
110
+ user.visits
111
+ ```
112
+
113
+ ## Location
114
+
115
+ Ahoy uses [Geocoder](https://github.com/alexreisner/geocoder) for IP-based geocoding.
116
+
117
+ ## UTM Parameters
118
+
119
+ Use UTM Parameters to track campaigns. [This is great for emails and social media](http://www.thunderseo.com/blog/utm-parameters/). Just add them to your links and Ahoy will pick them up.
120
+
121
+ ```
122
+ http://datakick.org/?utm_medium=email&utm_campaign=newsletter&utm_source=newsletter-2014-03
123
+ ```
124
+
125
+ or
126
+
127
+ ```
128
+ http://datakick.org/?utm_medium=twitter&utm_campaign=social&utm_source=tweet123
129
+ ```
130
+
68
131
  ## Features
69
132
 
70
133
  - Excludes bots
71
134
  - Degrades gracefully when cookies are disabled
72
- - Gets campaign from utm_campaign parameter
73
135
 
74
136
  ## TODO
75
137
 
76
- - better readme
77
- - model integration
78
- - update visit when user logs in
79
- - set visit_id automatically on `visitable` models
80
138
  - simple dashboard
81
139
  - hook to store additional fields
82
140
  - turn off modules
data/ahoy_matey.gemspec CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency "browser", ">= 0.4.0"
23
23
  spec.add_dependency "geocoder"
24
24
  spec.add_dependency "referer-parser"
25
+ spec.add_dependency "request_store"
25
26
 
26
27
  spec.add_development_dependency "bundler", "~> 1.5"
27
28
  spec.add_development_dependency "rake"
@@ -4,7 +4,7 @@ module Ahoy
4
4
 
5
5
  def create
6
6
  visit =
7
- Ahoy::Visit.new do |v|
7
+ Ahoy.visit_model.new do |v|
8
8
  v.visit_token = params[:visit_token]
9
9
  v.visitor_token = params[:visitor_token]
10
10
  v.ip = request.remote_ip
@@ -14,11 +14,6 @@ module Ahoy
14
14
  v.user = current_user if respond_to?(:current_user)
15
15
  end
16
16
 
17
- visit.set_traffic_source
18
- visit.set_technology
19
- visit.set_location
20
- visit.set_utm_parameters
21
-
22
17
  visit.save!
23
18
  render json: {id: visit.id}
24
19
  end
@@ -3,13 +3,16 @@ module Ahoy
3
3
 
4
4
  def self.included(base)
5
5
  base.helper_method :current_visit
6
+ base.before_filter do
7
+ RequestStore.store[:ahoy_controller] ||= self
8
+ end
6
9
  end
7
10
 
8
11
  protected
9
12
 
10
13
  def current_visit
11
14
  if cookies[:ahoy_visit]
12
- @current_visit ||= Ahoy::Visit.where(visit_token: cookies[:ahoy_visit]).first
15
+ @current_visit ||= Ahoy.visit_model.where(visit_token: cookies[:ahoy_visit]).first
13
16
  end
14
17
  end
15
18
 
@@ -0,0 +1,5 @@
1
+ module Ahoy
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Ahoy
4
+ end
5
+ end
data/lib/ahoy/model.rb ADDED
@@ -0,0 +1,99 @@
1
+ module Ahoy
2
+ module Model
3
+
4
+ def ahoy_visit
5
+ class_eval do
6
+
7
+ belongs_to :user, polymorphic: true
8
+
9
+ before_create :set_traffic_source
10
+ before_create :set_utm_parameters
11
+ before_create :set_technology
12
+ before_create :set_location
13
+
14
+ def set_traffic_source
15
+ referring_uri = Addressable::URI.parse(referrer) rescue nil
16
+ self.referring_domain = referring_uri.try(:host)
17
+ search_keyword = RefererParser::Referer.new(referrer).search_term rescue nil
18
+ self.search_keyword = search_keyword.present? ? search_keyword : nil
19
+ end
20
+
21
+ def set_utm_parameters
22
+ landing_uri = Addressable::URI.parse(landing_page) rescue nil
23
+ if landing_uri
24
+ query_values = landing_uri.query_values || {}
25
+ %w[utm_source utm_medium utm_term utm_content utm_campaign].each do |name|
26
+ self[name] = query_values[name]
27
+ end
28
+ end
29
+ end
30
+
31
+ def set_technology
32
+ browser = Browser.new(ua: user_agent)
33
+
34
+ self.browser = browser.name
35
+
36
+ # TODO add more
37
+ self.os =
38
+ if browser.android?
39
+ "Android"
40
+ elsif browser.ios?
41
+ "iOS"
42
+ elsif browser.windows_phone?
43
+ "Windows Phone"
44
+ elsif browser.blackberry?
45
+ "Blackberry"
46
+ elsif browser.chrome_os?
47
+ "Chrome OS"
48
+ elsif browser.mac?
49
+ "Mac"
50
+ elsif browser.windows?
51
+ "Windows"
52
+ elsif browser.linux?
53
+ "Linux"
54
+ end
55
+
56
+ self.device_type =
57
+ if browser.tv?
58
+ "TV"
59
+ elsif browser.console?
60
+ "Console"
61
+ elsif browser.tablet?
62
+ "Tablet"
63
+ elsif browser.mobile?
64
+ "Mobile"
65
+ else
66
+ "Desktop"
67
+ end
68
+ end
69
+
70
+ def set_location
71
+ location = Geocoder.search(ip).first rescue nil
72
+ if location
73
+ self.country = location.country.presence
74
+ self.region = location.state.presence
75
+ self.city = location.city.presence
76
+ end
77
+ end
78
+
79
+ end # end class_eval
80
+ end
81
+
82
+ def visitable
83
+ class_eval do
84
+ belongs_to :visit
85
+
86
+ before_create :set_visit
87
+
88
+ def set_visit
89
+ if !self.class.column_names.include?("visit_id")
90
+ raise "Add a visit_id column to this table to use visitable"
91
+ else
92
+ self.visit ||= RequestStore.store[:ahoy_controller].try(:send, :current_visit)
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ end
99
+ end
data/lib/ahoy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/ahoy_matey.rb CHANGED
@@ -1,28 +1,33 @@
1
- require "ahoy/version"
2
- require "ahoy/controller"
3
1
  require "addressable/uri"
4
2
  require "browser"
5
3
  require "geocoder"
6
4
  require "referer-parser"
5
+ require "request_store"
6
+ require "ahoy/version"
7
+ require "ahoy/controller"
8
+ require "ahoy/model"
9
+ require "ahoy/engine"
7
10
 
8
11
  module Ahoy
9
- class Engine < ::Rails::Engine
10
- isolate_namespace Ahoy
12
+
13
+ def self.visit_model
14
+ ::Visit
11
15
  end
16
+
12
17
  end
13
18
 
14
19
  ActionController::Base.send :include, Ahoy::Controller
20
+ ActiveRecord::Base.send(:extend, Ahoy::Model) if defined?(ActiveRecord)
15
21
 
16
22
  if defined?(Warden)
17
23
  Warden::Manager.after_authentication do |user, auth, opts|
18
- p user
19
- p auth.env
20
- p opts
21
24
  request = Rack::Request.new(auth.env)
22
25
  if request.cookies["ahoy_visit"]
23
- visit = Ahoy::Visit.where(visit_token: request.cookies["ahoy_visit"]).first
24
- visit.user = user
25
- visit.save!
26
+ visit = Ahoy.visit_model.where(visit_token: request.cookies["ahoy_visit"]).first
27
+ if visit
28
+ visit.user = user
29
+ visit.save!
30
+ end
26
31
  end
27
32
  end
28
33
  end
@@ -24,6 +24,15 @@ module Ahoy
24
24
  def copy_migration
25
25
  migration_template "install.rb", "db/migrate/install_ahoy.rb"
26
26
  end
27
+
28
+ def generate_model
29
+ invoke "active_record:model", ["Visit"], migration: false
30
+ end
31
+
32
+ def inject_ahoy_content
33
+ inject_into_class "app/models/visit.rb", "Visit", " ahoy_visit\n"
34
+ end
35
+
27
36
  end
28
37
  end
29
38
  end
@@ -1,6 +1,6 @@
1
1
  class <%= migration_class_name %> < ActiveRecord::Migration
2
2
  def change
3
- create_table :ahoy_visits do |t|
3
+ create_table :visits do |t|
4
4
  # cookies
5
5
  t.string :visit_token
6
6
  t.string :visitor_token
@@ -39,7 +39,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration
39
39
  t.timestamp :created_at
40
40
  end
41
41
 
42
- add_index :ahoy_visits, [:visit_token], unique: true
43
- add_index :ahoy_visits, [:user_id, :user_type]
42
+ add_index :visits, [:visit_token], unique: true
43
+ add_index :visits, [:user_id, :user_type]
44
44
  end
45
45
  end
@@ -63,7 +63,9 @@
63
63
  }
64
64
 
65
65
  function debug(message) {
66
- window.console.log(message, visitToken, visitorToken);
66
+ if (debugMode) {
67
+ window.console.log(message, visitToken, visitorToken);
68
+ }
67
69
  }
68
70
 
69
71
  // main
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ahoy_matey
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-02 00:00:00.000000000 Z
11
+ date: 2014-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: request_store
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -108,9 +122,10 @@ files:
108
122
  - Rakefile
109
123
  - ahoy_matey.gemspec
110
124
  - app/controllers/ahoy/visits_controller.rb
111
- - app/models/ahoy/visit.rb
112
125
  - config/routes.rb
113
126
  - lib/ahoy/controller.rb
127
+ - lib/ahoy/engine.rb
128
+ - lib/ahoy/model.rb
114
129
  - lib/ahoy/version.rb
115
130
  - lib/ahoy_matey.rb
116
131
  - lib/generators/ahoy/install_generator.rb
@@ -136,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
151
  version: '0'
137
152
  requirements: []
138
153
  rubyforge_project:
139
- rubygems_version: 2.2.0
154
+ rubygems_version: 2.2.2
140
155
  signing_key:
141
156
  specification_version: 4
142
157
  summary: Simple, powerful visit tracking for Rails
@@ -1,71 +0,0 @@
1
- module Ahoy
2
- class Visit < ActiveRecord::Base
3
- belongs_to :user, polymorphic: true
4
-
5
- def set_traffic_source
6
- referring_uri = Addressable::URI.parse(referrer) rescue nil
7
- self.referring_domain = referring_uri.try(:host)
8
- search_keyword = RefererParser::Referer.new(referrer).search_term rescue nil
9
- self.search_keyword = search_keyword.present? ? search_keyword : nil
10
- end
11
-
12
- def set_utm_parameters
13
- landing_uri = Addressable::URI.parse(landing_page) rescue nil
14
- if landing_uri
15
- query_values = landing_uri.query_values || {}
16
- %w[utm_source utm_medium utm_term utm_content utm_campaign].each do |name|
17
- self[name] = query_values[name]
18
- end
19
- end
20
- end
21
-
22
- def set_technology
23
- browser = Browser.new(ua: user_agent)
24
-
25
- self.browser = browser.name
26
-
27
- # TODO add more
28
- self.os =
29
- if browser.android?
30
- "Android"
31
- elsif browser.ios?
32
- "iOS"
33
- elsif browser.windows_phone?
34
- "Windows Phone"
35
- elsif browser.blackberry?
36
- "Blackberry"
37
- elsif browser.chrome_os?
38
- "Chrome OS"
39
- elsif browser.mac?
40
- "Mac"
41
- elsif browser.windows?
42
- "Windows"
43
- elsif browser.linux?
44
- "Linux"
45
- end
46
-
47
- self.device_type =
48
- if browser.tv?
49
- "TV"
50
- elsif browser.console?
51
- "Console"
52
- elsif browser.tablet?
53
- "Tablet"
54
- elsif browser.mobile?
55
- "Mobile"
56
- else
57
- "Desktop"
58
- end
59
- end
60
-
61
- def set_location
62
- location = Geocoder.search(ip).first rescue nil
63
- if location
64
- self.country = location.country.presence
65
- self.region = location.state.presence
66
- self.city = location.city.presence
67
- end
68
- end
69
-
70
- end
71
- end