ahoy_matey 3.3.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +17 -58
- data/app/controllers/ahoy/base_controller.rb +12 -4
- data/app/jobs/ahoy/geocode_v2_job.rb +2 -0
- data/lib/ahoy.rb +3 -8
- data/lib/ahoy/query_methods.rb +16 -40
- data/lib/ahoy/tracker.rb +1 -4
- data/lib/ahoy/version.rb +1 -1
- data/lib/generators/ahoy/templates/base_store_initializer.rb.tt +2 -2
- data/lib/generators/ahoy/templates/database_store_initializer.rb.tt +2 -2
- data/vendor/assets/javascripts/ahoy.js +6 -17
- metadata +5 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fb8aecda5242614f518d06dbdc9449305f0ed30677d667e01eb1edefc627bc7
|
4
|
+
data.tar.gz: 8f52fbe0bab0a0ac1c5722b06f342add3d31c0c441230b77f03ae566e07f746b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '059927d7fe2344882860ae81ff23e142a09ed955da818da8d3e679b03173b39e64ffc611e4e682a912901678cd9b790b461805f788c423cd2b4331c2a340c226'
|
7
|
+
data.tar.gz: f2d53c35500ee4d30485cfbf6c5d444cbf03c50cec4762783a972411343e19b8baf53b61286cc4aa78bbbe98a69df21da701989422263780447341fdce756db0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 4.0.0 (2021-08-14)
|
2
|
+
|
3
|
+
- Disabled geocoding by default
|
4
|
+
- Made the `geocoder` gem an optional dependency
|
5
|
+
- Updated Ahoy.js to 0.4.0
|
6
|
+
- Updated API to return 400 status code when missing required parameters
|
7
|
+
- Dropped support for Ruby < 2.6 and Rails < 5.2
|
8
|
+
|
1
9
|
## 3.3.0 (2021-08-13)
|
2
10
|
|
3
11
|
- Added `country_code` to geocoding
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
Track visits and events in Ruby, JavaScript, and native apps. Data is stored in your database by default, and you can customize it for any data store as you grow.
|
6
6
|
|
7
|
+
**Ahoy 4.0 was recently released** - see [how to upgrade](#upgrading)
|
8
|
+
|
7
9
|
:postbox: Check out [Ahoy Email](https://github.com/ankane/ahoy_email) for emails and [Field Test](https://github.com/ankane/field_test) for A/B testing
|
8
10
|
|
9
11
|
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
@@ -143,12 +145,6 @@ end
|
|
143
145
|
ahoy.track("Viewed book", {title: "The World is Flat"});
|
144
146
|
```
|
145
147
|
|
146
|
-
Track events automatically with:
|
147
|
-
|
148
|
-
```javascript
|
149
|
-
ahoy.trackAll();
|
150
|
-
```
|
151
|
-
|
152
148
|
See [Ahoy.js](https://github.com/ankane/ahoy.js) for a complete list of features.
|
153
149
|
|
154
150
|
#### Native Apps
|
@@ -350,7 +346,13 @@ Safely.report_exception_method = ->(e) { Rollbar.error(e) }
|
|
350
346
|
|
351
347
|
Ahoy uses [Geocoder](https://github.com/alexreisner/geocoder) for geocoding. We recommend configuring [local geocoding](#local-geocoding) or [load balancer geocoding](#load-balancer-geocoding) so IP addresses are not sent to a 3rd party service. If you do use a 3rd party service and adhere to GDPR, be sure to add it to your subprocessor list. If Ahoy is configured to [mask IPs](#ip-masking), the masked IP is used (this can reduce accuracy but is better for privacy).
|
352
348
|
|
353
|
-
To enable geocoding,
|
349
|
+
To enable geocoding, add this line to your application’s Gemfile:
|
350
|
+
|
351
|
+
```ruby
|
352
|
+
gem 'geocoder'
|
353
|
+
```
|
354
|
+
|
355
|
+
And update `config/initializers/ahoy.rb`:
|
354
356
|
|
355
357
|
```ruby
|
356
358
|
Ahoy.geocode = true
|
@@ -743,62 +745,19 @@ Send a `POST` request to `/ahoy/events` with `Content-Type: application/json` an
|
|
743
745
|
|
744
746
|
## Upgrading
|
745
747
|
|
746
|
-
###
|
747
|
-
|
748
|
-
If you installed Ahoy before 2.1 and want to keep legacy user agent parsing and bot detection, add to your Gemfile:
|
749
|
-
|
750
|
-
```ruby
|
751
|
-
gem "browser", "~> 2.0"
|
752
|
-
gem "user_agent_parser"
|
753
|
-
```
|
754
|
-
|
755
|
-
And add to `config/initializers/ahoy.rb`:
|
756
|
-
|
757
|
-
```ruby
|
758
|
-
Ahoy.user_agent_parser = :legacy
|
759
|
-
```
|
760
|
-
|
761
|
-
### 2.2
|
762
|
-
|
763
|
-
Ahoy now ships with better bot detection if you use Device Detector. This should be more accurate but can significantly reduce the number of visits recorded. For existing installs, it’s opt-in to start. To use it, add to `config/initializers/ahoy.rb`:
|
764
|
-
|
765
|
-
```ruby
|
766
|
-
Ahoy.bot_detection_version = 2
|
767
|
-
```
|
768
|
-
|
769
|
-
### 2.1
|
770
|
-
|
771
|
-
Ahoy recommends [Device Detector](https://github.com/podigee/device_detector) for user agent parsing and makes it the default for new installations. To switch, add to `config/initializers/ahoy.rb`:
|
748
|
+
### 4.0
|
772
749
|
|
773
|
-
|
774
|
-
Ahoy.user_agent_parser = :device_detector
|
775
|
-
```
|
750
|
+
There are two notable changes to geocoding:
|
776
751
|
|
777
|
-
|
778
|
-
|
779
|
-
```ruby
|
780
|
-
Ahoy::Visit.find_each do |visit|
|
781
|
-
client = DeviceDetector.new(visit.user_agent)
|
782
|
-
device_type =
|
783
|
-
case client.device_type
|
784
|
-
when "smartphone"
|
785
|
-
"Mobile"
|
786
|
-
when "tv"
|
787
|
-
"TV"
|
788
|
-
else
|
789
|
-
client.device_type.try(:titleize)
|
790
|
-
end
|
752
|
+
1. Geocoding is now disabled by default (this was already the case for new installations with 3.2.0+). Check out the instructions for [how to enable it](#geocoding).
|
791
753
|
|
792
|
-
|
793
|
-
visit.os = client.os_name
|
794
|
-
visit.device_type = device_type
|
795
|
-
visit.save(validate: false) if visit.changed?
|
796
|
-
end
|
797
|
-
```
|
754
|
+
2. The `geocoder` gem is now an optional dependency. To use geocoding, add it to your Gemfile:
|
798
755
|
|
799
|
-
|
756
|
+
```ruby
|
757
|
+
gem 'geocoder'
|
758
|
+
```
|
800
759
|
|
801
|
-
|
760
|
+
Also, check out the [upgrade notes](https://github.com/ankane/ahoy.js#upgrading) for Ahoy.js.
|
802
761
|
|
803
762
|
## History
|
804
763
|
|
@@ -5,19 +5,27 @@ module Ahoy
|
|
5
5
|
skip_after_action(*filters, raise: false)
|
6
6
|
skip_around_action(*filters, raise: false)
|
7
7
|
|
8
|
-
before_action :verify_request_size
|
9
|
-
before_action :renew_cookies
|
10
|
-
|
11
8
|
if respond_to?(:protect_from_forgery)
|
12
9
|
protect_from_forgery with: :null_session, if: -> { Ahoy.protect_from_forgery }
|
13
10
|
end
|
14
11
|
|
12
|
+
before_action :verify_request_size
|
13
|
+
before_action :check_params
|
14
|
+
before_action :renew_cookies
|
15
|
+
|
15
16
|
protected
|
16
17
|
|
17
18
|
def ahoy
|
18
19
|
@ahoy ||= Ahoy::Tracker.new(controller: self, api: true)
|
19
20
|
end
|
20
21
|
|
22
|
+
def check_params
|
23
|
+
if ahoy.send(:missing_params?)
|
24
|
+
logger.info "[ahoy] Missing required parameters"
|
25
|
+
render plain: "Missing required parameters\n", status: :bad_request
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
21
29
|
# set proper ttl if cookie generated from JavaScript
|
22
30
|
# approach is not perfect, as user must reload the page
|
23
31
|
# for new cookie settings to take effect
|
@@ -28,7 +36,7 @@ module Ahoy
|
|
28
36
|
def verify_request_size
|
29
37
|
if request.content_length > Ahoy.max_content_length
|
30
38
|
logger.info "[ahoy] Payload too large"
|
31
|
-
render plain: "Payload too large\n", status:
|
39
|
+
render plain: "Payload too large\n", status: :payload_too_large
|
32
40
|
end
|
33
41
|
end
|
34
42
|
end
|
data/lib/ahoy.rb
CHANGED
@@ -4,7 +4,6 @@ require "ipaddr"
|
|
4
4
|
# dependencies
|
5
5
|
require "active_support"
|
6
6
|
require "active_support/core_ext"
|
7
|
-
require "geocoder"
|
8
7
|
require "safely/core"
|
9
8
|
|
10
9
|
# modules
|
@@ -44,7 +43,7 @@ module Ahoy
|
|
44
43
|
self.quiet = true
|
45
44
|
|
46
45
|
mattr_accessor :geocode
|
47
|
-
self.geocode =
|
46
|
+
self.geocode = false
|
48
47
|
|
49
48
|
mattr_accessor :max_content_length
|
50
49
|
self.max_content_length = 8192
|
@@ -128,10 +127,6 @@ ActiveSupport.on_load(:action_view) do
|
|
128
127
|
end
|
129
128
|
|
130
129
|
# Mongoid
|
131
|
-
|
132
|
-
|
133
|
-
# Mongoid::Document::ClassMethods.include(Ahoy::Model)
|
134
|
-
# end
|
135
|
-
if defined?(ActiveModel)
|
136
|
-
ActiveModel::Callbacks.include(Ahoy::Model)
|
130
|
+
ActiveSupport.on_load(:mongoid) do
|
131
|
+
Mongoid::Document::ClassMethods.include(Ahoy::Model)
|
137
132
|
end
|
data/lib/ahoy/query_methods.rb
CHANGED
@@ -19,35 +19,21 @@ module Ahoy
|
|
19
19
|
when "mongoid"
|
20
20
|
relation = where(Hash[properties.map { |k, v| ["properties.#{k}", v] }])
|
21
21
|
when /mysql/
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
relation = relation.where("JSON_UNQUOTE(properties -> ?) = ?", "$.#{k}", v.as_json)
|
31
|
-
end
|
32
|
-
else
|
33
|
-
properties.each do |k, v|
|
34
|
-
# TODO cast to json instead
|
35
|
-
relation = relation.where("properties REGEXP ?", "[{,]#{{k.to_s => v}.to_json.sub(/\A\{/, "").sub(/\}\z/, "").gsub("+", "\\\\+")}[,}]")
|
22
|
+
column = column_type == :json || connection.try(:mariadb?) ? "properties" : "CAST(properties AS JSON)"
|
23
|
+
properties.each do |k, v|
|
24
|
+
if v.nil?
|
25
|
+
v = "null"
|
26
|
+
elsif v == true
|
27
|
+
v = "true"
|
36
28
|
end
|
29
|
+
|
30
|
+
relation = relation.where("JSON_UNQUOTE(JSON_EXTRACT(#{column}, ?)) = ?", "$.#{k}", v.as_json)
|
37
31
|
end
|
38
32
|
when /postgres|postgis/
|
39
|
-
|
33
|
+
case column_type
|
34
|
+
when :jsonb
|
40
35
|
relation = relation.where("properties @> ?", properties.to_json)
|
41
|
-
|
42
|
-
properties.each do |k, v|
|
43
|
-
relation =
|
44
|
-
if v.nil?
|
45
|
-
relation.where("properties ->> ? IS NULL", k.to_s)
|
46
|
-
else
|
47
|
-
relation.where("properties ->> ? = ?", k.to_s, v.as_json.to_s)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
elsif column_type == :hstore
|
36
|
+
when :hstore
|
51
37
|
properties.each do |k, v|
|
52
38
|
relation =
|
53
39
|
if v.nil?
|
@@ -57,10 +43,7 @@ module Ahoy
|
|
57
43
|
end
|
58
44
|
end
|
59
45
|
else
|
60
|
-
properties
|
61
|
-
# TODO cast to jsonb instead
|
62
|
-
relation = relation.where("properties SIMILAR TO ?", "%[{,]#{{k.to_s => v}.to_json.sub(/\A\{/, "").sub(/\}\z/, "").gsub("+", "\\\\+")}[,}]%")
|
63
|
-
end
|
46
|
+
relation = relation.where("properties::jsonb @> ?", properties.to_json)
|
64
47
|
end
|
65
48
|
else
|
66
49
|
raise "Adapter not supported: #{adapter_name}"
|
@@ -84,17 +67,10 @@ module Ahoy
|
|
84
67
|
when "mongoid"
|
85
68
|
raise "Adapter not supported: #{adapter_name}"
|
86
69
|
when /mysql/
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
92
|
-
else
|
93
|
-
column = column_type == :json ? "properties" : "CAST(properties AS JSON)"
|
94
|
-
props.each do |prop|
|
95
|
-
quoted_prop = connection.quote("$.#{prop}")
|
96
|
-
relation = relation.group("JSON_UNQUOTE(JSON_EXTRACT(#{column}, #{quoted_prop}))")
|
97
|
-
end
|
70
|
+
column = column_type == :json || connection.try(:mariadb?) ? "properties" : "CAST(properties AS JSON)"
|
71
|
+
props.each do |prop|
|
72
|
+
quoted_prop = connection.quote("$.#{prop}")
|
73
|
+
relation = relation.group("JSON_UNQUOTE(JSON_EXTRACT(#{column}, #{quoted_prop}))")
|
98
74
|
end
|
99
75
|
when /postgres|postgis/
|
100
76
|
# convert to jsonb to fix
|
data/lib/ahoy/tracker.rb
CHANGED
@@ -19,8 +19,6 @@ module Ahoy
|
|
19
19
|
def track(name, properties = {}, options = {})
|
20
20
|
if exclude?
|
21
21
|
debug "Event excluded"
|
22
|
-
elsif missing_params?
|
23
|
-
debug "Missing required parameters"
|
24
22
|
else
|
25
23
|
data = {
|
26
24
|
visit_token: visit_token,
|
@@ -41,8 +39,6 @@ module Ahoy
|
|
41
39
|
def track_visit(defer: false, started_at: nil)
|
42
40
|
if exclude?
|
43
41
|
debug "Visit excluded"
|
44
|
-
elsif missing_params?
|
45
|
-
debug "Missing required parameters"
|
46
42
|
else
|
47
43
|
if defer
|
48
44
|
set_cookie("ahoy_track", true, nil, false)
|
@@ -155,6 +151,7 @@ module Ahoy
|
|
155
151
|
@options[:api]
|
156
152
|
end
|
157
153
|
|
154
|
+
# private, but used by API
|
158
155
|
def missing_params?
|
159
156
|
if Ahoy.cookies && api? && Ahoy.protect_from_forgery
|
160
157
|
!(existing_visit_token && existing_visitor_token)
|
data/lib/ahoy/version.rb
CHANGED
@@ -19,7 +19,7 @@ end
|
|
19
19
|
# set to true for JavaScript tracking
|
20
20
|
Ahoy.api = false
|
21
21
|
|
22
|
-
# set to true for geocoding
|
23
|
-
# we recommend configuring local geocoding
|
22
|
+
# set to true for geocoding (and add the geocoder gem to your Gemfile)
|
23
|
+
# we recommend configuring local geocoding as well
|
24
24
|
# see https://github.com/ankane/ahoy#geocoding
|
25
25
|
Ahoy.geocode = false
|
@@ -4,7 +4,7 @@ end
|
|
4
4
|
# set to true for JavaScript tracking
|
5
5
|
Ahoy.api = false
|
6
6
|
|
7
|
-
# set to true for geocoding
|
8
|
-
# we recommend configuring local geocoding
|
7
|
+
# set to true for geocoding (and add the geocoder gem to your Gemfile)
|
8
|
+
# we recommend configuring local geocoding as well
|
9
9
|
# see https://github.com/ankane/ahoy#geocoding
|
10
10
|
Ahoy.geocode = false
|
@@ -2,7 +2,7 @@
|
|
2
2
|
* Ahoy.js
|
3
3
|
* Simple, powerful JavaScript analytics
|
4
4
|
* https://github.com/ankane/ahoy.js
|
5
|
-
* v0.
|
5
|
+
* v0.4.0
|
6
6
|
* MIT License
|
7
7
|
*/
|
8
8
|
|
@@ -26,7 +26,7 @@
|
|
26
26
|
if (domain) {
|
27
27
|
cookieDomain = "; domain=" + domain;
|
28
28
|
}
|
29
|
-
document.cookie = name + "=" + escape(value) + expires + cookieDomain + "; path
|
29
|
+
document.cookie = name + "=" + escape(value) + expires + cookieDomain + "; path=/; samesite=lax";
|
30
30
|
},
|
31
31
|
get: function (name) {
|
32
32
|
var i, c;
|
@@ -478,8 +478,7 @@
|
|
478
478
|
|
479
479
|
ahoy.trackClicks = function (selector) {
|
480
480
|
if (selector === undefined) {
|
481
|
-
|
482
|
-
selector = "a, button, input[type=submit]";
|
481
|
+
throw new Error("Missing selector");
|
483
482
|
}
|
484
483
|
onEvent("click", selector, function (e) {
|
485
484
|
var properties = eventProperties.call(this, e);
|
@@ -491,8 +490,7 @@
|
|
491
490
|
|
492
491
|
ahoy.trackSubmits = function (selector) {
|
493
492
|
if (selector === undefined) {
|
494
|
-
|
495
|
-
selector = "form";
|
493
|
+
throw new Error("Missing selector");
|
496
494
|
}
|
497
495
|
onEvent("submit", selector, function (e) {
|
498
496
|
var properties = eventProperties.call(this, e);
|
@@ -501,10 +499,9 @@
|
|
501
499
|
};
|
502
500
|
|
503
501
|
ahoy.trackChanges = function (selector) {
|
502
|
+
log("trackChanges is deprecated and will be removed in 0.5.0");
|
504
503
|
if (selector === undefined) {
|
505
|
-
|
506
|
-
log("trackChanges is deprecated and will be removed in 0.4.0");
|
507
|
-
selector = "input, textarea, select";
|
504
|
+
throw new Error("Missing selector");
|
508
505
|
}
|
509
506
|
onEvent("change", selector, function (e) {
|
510
507
|
var properties = eventProperties.call(this, e);
|
@@ -512,14 +509,6 @@
|
|
512
509
|
});
|
513
510
|
};
|
514
511
|
|
515
|
-
ahoy.trackAll = function() {
|
516
|
-
log("trackAll is deprecated and will be removed in 0.4.0");
|
517
|
-
ahoy.trackView();
|
518
|
-
ahoy.trackClicks("a, button, input[type=submit]");
|
519
|
-
ahoy.trackSubmits("form");
|
520
|
-
ahoy.trackChanges("input, textarea, select");
|
521
|
-
};
|
522
|
-
|
523
512
|
// push events from queue
|
524
513
|
try {
|
525
514
|
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:
|
4
|
+
version: 4.0.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: 2021-08-
|
11
|
+
date: 2021-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,28 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '5'
|
19
|
+
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '5'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: geocoder
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 1.4.5
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 1.4.5
|
26
|
+
version: '5.2'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: safely_block
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,7 +106,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
106
|
requirements:
|
121
107
|
- - ">="
|
122
108
|
- !ruby/object:Gem::Version
|
123
|
-
version: '2.
|
109
|
+
version: '2.6'
|
124
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
111
|
requirements:
|
126
112
|
- - ">="
|