ahoy_matey 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1aebb95363cb98c2b74dadb3b42f9cd04c17c421
4
- data.tar.gz: 08785d2aa638fddb3881d4365e74ded3049cfec8
3
+ metadata.gz: 40222ba157a73c4362b78a26fe1796a9bbc9fb50
4
+ data.tar.gz: 58a88b0ed382c126ceb141c902855f5c1492ee77
5
5
  SHA512:
6
- metadata.gz: 16c58280be2b7a51a4f41c837204f701a93897b509330a0ff648d06819e2b944373fcaf5e0b595009270f5b332ec1ef81626537b824deafbd2f89cca5ece4376
7
- data.tar.gz: 2aeb6f81dd3f0fdf09d0aee20ba52ed9349903636b9b392e87782ae135161520809aa45549dca292a479d5bae95ba893c4e6f95b29e13f6d32c601a39e204aae
6
+ metadata.gz: e04afdc9015e4456e2062c718c38ef043777b3e7442435926420db88bbeecb5226b60d899d45b24d69faa9cadb4041f735a7460f6f8f0062180763c90fdadc8d
7
+ data.tar.gz: 08de05c386b58857803d8867f92512293f68d41146d1c96d3e0c7082596ab4db0f0b920284ae28a9ffa946877440abe96279d2765b2cc030d68a65b6da62f9b6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 1.5.0
2
+
3
+ - Removed throttling due to unintended side effects with its implementation
4
+ - Ensure basic token requirements
5
+ - Fixed visit recreation on cookie expiration
6
+ - Fixed issue where `/ahoy/visits` is called indefinitely when `Ahoy.cookie_domain = :all`
7
+
1
8
  ## 1.4.2
2
9
 
3
10
  - Fixed issues with `where_properties`
data/README.md CHANGED
@@ -440,7 +440,9 @@ Ahoy.quiet = false
440
440
 
441
441
  How you explore the data depends on the data store used.
442
442
 
443
- Here are ways to do it with ActiveRecord.
443
+ For SQL databases, you can use [Blazer](https://github.com/ankane/blazer) to easily generate charts and dashboards.
444
+
445
+ With ActiveRecord, you can do:
444
446
 
445
447
  ```ruby
446
448
  Visit.group(:search_keyword).count
@@ -448,7 +450,7 @@ Visit.group(:country).count
448
450
  Visit.group(:referring_domain).count
449
451
  ```
450
452
 
451
- [Chartkick](http://chartkick.com/) and [Groupdate](https://github.com/ankane/groupdate) make it super easy to visualize the data.
453
+ [Chartkick](http://chartkick.com/) and [Groupdate](https://github.com/ankane/groupdate) make it easy to visualize the data.
452
454
 
453
455
  ```erb
454
456
  <%= line_chart Visit.group_by_day(:started_at).count %>
@@ -528,6 +530,18 @@ Send a `POST` request as `Content-Type: application/json` to `/ahoy/events` with
528
530
 
529
531
  Use an array to pass multiple events at once.
530
532
 
533
+ ## Throttling
534
+
535
+ To throttle requests to Ahoy endpoints, check out [Rack::Attack](https://github.com/kickstarter/ack-attack). Here’s a sample config:
536
+
537
+ ```ruby
538
+ Rack::Attack.throttle("ahoy/ip", limit: 20, period: 1.minute) do |req|
539
+ if req.path.start_with?("/ahoy/")
540
+ req.ip
541
+ end
542
+ end
543
+ ```
544
+
531
545
  ## Reference
532
546
 
533
547
  By default, Ahoy create endpoints at `/ahoy/visits` and `/ahoy/events`. To disable, use:
@@ -538,6 +552,10 @@ Ahoy.mount = false
538
552
 
539
553
  ## Upgrading
540
554
 
555
+ ### 1.5.0
556
+
557
+ There’s nothing to do, but it’s worth noting that simple throttling, which was added in `1.3.0`, was removed due to unintended side effects with its implementation. See the [Throttling](#throttling) section for how to properly add it by hand if needed.
558
+
541
559
  ### 1.4.0
542
560
 
543
561
  There’s nothing to do, but it’s worth noting the default store was changed from `ActiveRecordStore` to `ActiveRecordTokenStore` for new installations.
data/ahoy_matey.gemspec CHANGED
@@ -27,7 +27,6 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency "request_store"
28
28
  spec.add_dependency "uuidtools"
29
29
  spec.add_dependency "safely_block", ">= 0.1.1"
30
- spec.add_dependency "rack-attack"
31
30
 
32
31
  spec.add_development_dependency "bundler", "~> 1.5"
33
32
  spec.add_development_dependency "rake"
@@ -2,8 +2,13 @@ module Ahoy
2
2
  class BaseController < ApplicationController
3
3
  # skip all filters except for authlogic
4
4
  filters = _process_action_callbacks.map(&:filter) - [:load_authlogic]
5
- if respond_to?(:skip_action)
6
- skip_action *filters
5
+ if Rails::VERSION::MAJOR >= 5
6
+ skip_before_action(*filters, raise: false)
7
+ skip_after_action(*filters, raise: false)
8
+ skip_around_action(*filters, raise: false)
9
+ before_action :verify_request_size
10
+ elsif respond_to?(:skip_action_callback)
11
+ skip_action_callback *filters
7
12
  before_action :verify_request_size
8
13
  else
9
14
  skip_filter *filters
data/lib/ahoy.rb CHANGED
@@ -72,15 +72,6 @@ module Ahoy
72
72
  mattr_accessor :mount
73
73
  self.mount = true
74
74
 
75
- mattr_accessor :throttle
76
- self.throttle = true
77
-
78
- mattr_accessor :throttle_limit
79
- self.throttle_limit = 20
80
-
81
- mattr_accessor :throttle_period
82
- self.throttle_period = 1.minute
83
-
84
75
  mattr_accessor :job_queue
85
76
  self.job_queue = :ahoy
86
77
 
data/lib/ahoy/engine.rb CHANGED
@@ -1,11 +1,6 @@
1
1
  module Ahoy
2
2
  class Engine < ::Rails::Engine
3
3
  initializer "ahoy.middleware", after: "sprockets.environment" do |app|
4
- if Ahoy.throttle
5
- require "ahoy/throttle"
6
- app.middleware.use Ahoy::Throttle
7
- end
8
-
9
4
  next unless Ahoy.quiet
10
5
 
11
6
  # Parse PATH_INFO by assets prefix
data/lib/ahoy/tracker.rb CHANGED
@@ -30,7 +30,7 @@ module Ahoy
30
30
  debug "Visit excluded"
31
31
  else
32
32
  if options[:defer]
33
- set_cookie("ahoy_track", true)
33
+ set_cookie("ahoy_track", true, nil, false)
34
34
  else
35
35
  options = options.dup
36
36
 
@@ -60,11 +60,11 @@ module Ahoy
60
60
  end
61
61
 
62
62
  def visit_id
63
- @visit_id ||= ensure_uuid(existing_visit_id || visit_token)
63
+ @visit_id ||= ensure_uuid(existing_visit_id || visit_token_helper)
64
64
  end
65
65
 
66
66
  def visitor_id
67
- @visitor_id ||= ensure_uuid(existing_visitor_id || visitor_token)
67
+ @visitor_id ||= ensure_uuid(existing_visitor_id || visitor_token_helper)
68
68
  end
69
69
 
70
70
  def new_visit?
@@ -90,25 +90,31 @@ module Ahoy
90
90
  @visit_properties ||= Ahoy::VisitProperties.new(request, @options.slice(:api))
91
91
  end
92
92
 
93
- # for ActiveRecordTokenStore only - do not use
94
93
  def visit_token
95
- @visit_token ||= existing_visit_id || (@options[:api] && request.params["visit_token"]) || generate_id
94
+ @visit_token ||= ensure_token(visit_token_helper)
96
95
  end
97
96
 
98
- # for ActiveRecordTokenStore only - do not use
99
97
  def visitor_token
100
- @visitor_token ||= existing_visitor_id || (@options[:api] && request.params["visitor_token"]) || generate_id
98
+ @visitor_token ||= ensure_token(visitor_token_helper)
101
99
  end
102
100
 
103
101
  protected
104
102
 
105
- def set_cookie(name, value, duration = nil)
103
+ def visit_token_helper
104
+ @visit_token_helper ||= existing_visit_id || (@options[:api] && request.params["visit_token"]) || generate_id
105
+ end
106
+
107
+ def visitor_token_helper
108
+ @visitor_token_helper ||= existing_visitor_id || (@options[:api] && request.params["visitor_token"]) || generate_id
109
+ end
110
+
111
+ def set_cookie(name, value, duration = nil, use_domain = true)
106
112
  cookie = {
107
113
  value: value
108
114
  }
109
115
  cookie[:expires] = duration.from_now if duration
110
116
  domain = Ahoy.cookie_domain || Ahoy.domain
111
- cookie[:domain] = domain if domain
117
+ cookie[:domain] = domain if domain && use_domain
112
118
  request.cookie_jar[name] = cookie
113
119
  end
114
120
 
@@ -151,6 +157,10 @@ module Ahoy
151
157
  Ahoy.ensure_uuid(id)
152
158
  end
153
159
 
160
+ def ensure_token(token)
161
+ token.to_s.gsub(/[^a-z0-9\-]/i, "").first(64)
162
+ end
163
+
154
164
  def debug(message)
155
165
  Rails.logger.debug { "[ahoy] #{message}" }
156
166
  end
data/lib/ahoy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "1.4.2"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -8,11 +8,11 @@ module Ahoy
8
8
 
9
9
  KEYS = REQUEST_KEYS + TRAFFIC_SOURCE_KEYS + UTM_PARAMETER_KEYS + TECHNOLOGY_KEYS + LOCATION_KEYS
10
10
 
11
- delegate *REQUEST_KEYS, to: :request_deckhand
12
- delegate *TRAFFIC_SOURCE_KEYS, to: :traffic_source_deckhand
13
- delegate *(UTM_PARAMETER_KEYS + [:landing_params]), to: :utm_parameter_deckhand
14
- delegate *TECHNOLOGY_KEYS, to: :technology_deckhand
15
- delegate *LOCATION_KEYS, to: :location_deckhand
11
+ delegate(*REQUEST_KEYS, to: :request_deckhand)
12
+ delegate(*TRAFFIC_SOURCE_KEYS, to: :traffic_source_deckhand)
13
+ delegate(*(UTM_PARAMETER_KEYS + [:landing_params]), to: :utm_parameter_deckhand)
14
+ delegate(*TECHNOLOGY_KEYS, to: :technology_deckhand)
15
+ delegate(*LOCATION_KEYS, to: :location_deckhand)
16
16
 
17
17
  def initialize(request, options = {})
18
18
  @request = request
@@ -20,8 +20,9 @@
20
20
  var queue = [];
21
21
  var canStringify = typeof(JSON) !== "undefined" && typeof(JSON.stringify) !== "undefined";
22
22
  var eventQueue = [];
23
- var visitsUrl = ahoy.visitsUrl || "/ahoy/visits"
24
- var eventsUrl = ahoy.eventsUrl || "/ahoy/events"
23
+ var visitsUrl = ahoy.visitsUrl || "/ahoy/visits";
24
+ var eventsUrl = ahoy.eventsUrl || "/ahoy/events";
25
+ var canTrackNow = ahoy.trackNow && canStringify && typeof(window.navigator.sendBeacon) !== "undefined";
25
26
 
26
27
  // cookies
27
28
 
@@ -122,6 +123,13 @@
122
123
  });
123
124
  }
124
125
 
126
+ function trackEventNow(event) {
127
+ ready( function () {
128
+ var payload = new Blob([JSON.stringify([event])], {type : "application/json; charset=utf-8"});
129
+ navigator.sendBeacon(eventsUrl, payload)
130
+ });
131
+ }
132
+
125
133
  function page() {
126
134
  return ahoy.page || window.location.pathname;
127
135
  }
@@ -137,64 +145,66 @@
137
145
  };
138
146
  }
139
147
 
140
- // main
141
-
142
- visitId = getCookie("ahoy_visit");
143
- visitorId = getCookie("ahoy_visitor");
144
- track = getCookie("ahoy_track");
148
+ function createVisit() {
149
+ isReady = false;
145
150
 
146
- if (visitId && visitorId && !track) {
147
- // TODO keep visit alive?
148
- log("Active visit");
149
- setReady();
150
- } else {
151
- if (track) {
152
- destroyCookie("ahoy_track");
153
- }
154
-
155
- if (!visitId) {
156
- visitId = generateId();
157
- setCookie("ahoy_visit", visitId, visitTtl);
158
- }
151
+ visitId = ahoy.getVisitId();
152
+ visitorId = ahoy.getVisitorId();
153
+ track = getCookie("ahoy_track");
159
154
 
160
- // make sure cookies are enabled
161
- if (getCookie("ahoy_visit")) {
162
- log("Visit started");
163
-
164
- if (!visitorId) {
165
- visitorId = generateId();
166
- setCookie("ahoy_visitor", visitorId, visitorTtl);
155
+ if (visitId && visitorId && !track) {
156
+ // TODO keep visit alive?
157
+ log("Active visit");
158
+ setReady();
159
+ } else {
160
+ if (track) {
161
+ destroyCookie("ahoy_track");
167
162
  }
168
163
 
169
- var data = {
170
- visit_token: visitId,
171
- visitor_token: visitorId,
172
- platform: ahoy.platform || "Web",
173
- landing_page: window.location.href,
174
- screen_width: window.screen.width,
175
- screen_height: window.screen.height
176
- };
177
-
178
- // referrer
179
- if (document.referrer.length > 0) {
180
- data.referrer = document.referrer;
164
+ if (!visitId) {
165
+ visitId = generateId();
166
+ setCookie("ahoy_visit", visitId, visitTtl);
181
167
  }
182
168
 
183
- log(data);
184
-
185
- $.post(visitsUrl, data, setReady, "json");
186
- } else {
187
- log("Cookies disabled");
188
- setReady();
169
+ // make sure cookies are enabled
170
+ if (getCookie("ahoy_visit")) {
171
+ log("Visit started");
172
+
173
+ if (!visitorId) {
174
+ visitorId = generateId();
175
+ setCookie("ahoy_visitor", visitorId, visitorTtl);
176
+ }
177
+
178
+ var data = {
179
+ visit_token: visitId,
180
+ visitor_token: visitorId,
181
+ platform: ahoy.platform || "Web",
182
+ landing_page: window.location.href,
183
+ screen_width: window.screen.width,
184
+ screen_height: window.screen.height
185
+ };
186
+
187
+ // referrer
188
+ if (document.referrer.length > 0) {
189
+ data.referrer = document.referrer;
190
+ }
191
+
192
+ log(data);
193
+
194
+ $.post(visitsUrl, data, setReady, "json");
195
+ } else {
196
+ log("Cookies disabled");
197
+ setReady();
198
+ }
189
199
  }
190
200
  }
191
201
 
192
202
  ahoy.getVisitId = ahoy.getVisitToken = function () {
193
- return visitId;
203
+ return getCookie("ahoy_visit");
194
204
  };
195
205
 
196
206
  ahoy.getVisitorId = ahoy.getVisitorToken = function () {
197
- return visitorId;
207
+ return getCookie("ahoy_visitor");
198
208
  };
199
209
 
200
210
  ahoy.reset = function () {
@@ -215,22 +225,32 @@
215
225
  };
216
226
 
217
227
  ahoy.track = function (name, properties) {
228
+ if (!ahoy.getVisitId()) {
229
+ createVisit();
230
+ }
231
+
218
232
  // generate unique id
219
233
  var event = {
220
234
  id: generateId(),
235
+ visit_token: ahoy.getVisitId(),
236
+ visitor_token: ahoy.getVisitorId(),
221
237
  name: name,
222
238
  properties: properties,
223
239
  time: (new Date()).getTime() / 1000.0
224
240
  };
225
241
  log(event);
226
242
 
227
- eventQueue.push(event);
228
- saveEventQueue();
243
+ if (canTrackNow) {
244
+ trackEventNow(event);
245
+ } else {
246
+ eventQueue.push(event);
247
+ saveEventQueue();
229
248
 
230
- // wait in case navigating to reduce duplicate events
231
- setTimeout( function () {
232
- trackEvent(event);
233
- }, 1000);
249
+ // wait in case navigating to reduce duplicate events
250
+ setTimeout( function () {
251
+ trackEvent(event);
252
+ }, 1000);
253
+ }
234
254
  };
235
255
 
236
256
  ahoy.trackView = function () {
@@ -273,6 +293,8 @@
273
293
  ahoy.trackChanges();
274
294
  };
275
295
 
296
+ createVisit();
297
+
276
298
  // push events from queue
277
299
  try {
278
300
  eventQueue = JSON.parse(getCookie("ahoy_events") || "[]");
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: 1.4.2
4
+ version: 1.5.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: 2016-06-21 00:00:00.000000000 Z
11
+ date: 2016-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -136,20 +136,6 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: 0.1.1
139
- - !ruby/object:Gem::Dependency
140
- name: rack-attack
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :runtime
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
139
  - !ruby/object:Gem::Dependency
154
140
  name: bundler
155
141
  requirement: !ruby/object:Gem::Requirement
@@ -274,7 +260,6 @@ files:
274
260
  - lib/ahoy/stores/log_store.rb
275
261
  - lib/ahoy/stores/mongoid_store.rb
276
262
  - lib/ahoy/subscribers/active_record.rb
277
- - lib/ahoy/throttle.rb
278
263
  - lib/ahoy/tracker.rb
279
264
  - lib/ahoy/version.rb
280
265
  - lib/ahoy/visit_properties.rb
@@ -335,7 +320,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
335
320
  version: '0'
336
321
  requirements: []
337
322
  rubyforge_project:
338
- rubygems_version: 2.4.5.1
323
+ rubygems_version: 2.6.1
339
324
  signing_key:
340
325
  specification_version: 4
341
326
  summary: Simple, powerful visit tracking for Rails
@@ -348,3 +333,4 @@ test_files:
348
333
  - test/properties/postgresql_text_test.rb
349
334
  - test/test_helper.rb
350
335
  - test/visit_properties_test.rb
336
+ has_rdoc:
data/lib/ahoy/throttle.rb DELETED
@@ -1,17 +0,0 @@
1
- require "rack/attack"
2
-
3
- module Ahoy
4
- class Throttle < Rack::Attack
5
- throttle("ahoy/ip", limit: Ahoy.throttle_limit, period: Ahoy.throttle_period) do |req|
6
- if req.path.start_with?("/ahoy/")
7
- req.ip
8
- end
9
- end
10
-
11
- def_delegators self, :whitelisted?, :blacklisted?, :throttled?, :tracked?
12
-
13
- def self.throttled_response
14
- Rack::Attack.throttled_response
15
- end
16
- end
17
- end