ahoy_matey 2.0.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +112 -37
  3. data/CONTRIBUTING.md +9 -7
  4. data/LICENSE.txt +1 -1
  5. data/README.md +377 -63
  6. data/app/controllers/ahoy/base_controller.rb +14 -10
  7. data/app/controllers/ahoy/events_controller.rb +1 -1
  8. data/app/controllers/ahoy/visits_controller.rb +1 -0
  9. data/app/jobs/ahoy/geocode_v2_job.rb +3 -4
  10. data/lib/ahoy.rb +57 -2
  11. data/lib/ahoy/base_store.rb +32 -3
  12. data/lib/ahoy/controller.rb +21 -8
  13. data/lib/ahoy/database_store.rb +33 -16
  14. data/lib/ahoy/engine.rb +3 -1
  15. data/lib/ahoy/helper.rb +40 -0
  16. data/lib/ahoy/model.rb +2 -2
  17. data/lib/ahoy/query_methods.rb +46 -1
  18. data/lib/ahoy/tracker.rb +59 -27
  19. data/lib/ahoy/utils.rb +7 -0
  20. data/lib/ahoy/version.rb +1 -1
  21. data/lib/ahoy/visit_properties.rb +73 -37
  22. data/lib/generators/ahoy/activerecord_generator.rb +17 -26
  23. data/lib/generators/ahoy/base_generator.rb +1 -1
  24. data/lib/generators/ahoy/install_generator.rb +1 -1
  25. data/lib/generators/ahoy/mongoid_generator.rb +1 -5
  26. data/lib/generators/ahoy/templates/active_record_event_model.rb.tt +10 -0
  27. data/lib/generators/ahoy/templates/{active_record_migration.rb → active_record_migration.rb.tt} +14 -7
  28. data/lib/generators/ahoy/templates/active_record_visit_model.rb.tt +6 -0
  29. data/lib/generators/ahoy/templates/{base_store_initializer.rb → base_store_initializer.rb.tt} +8 -0
  30. data/lib/generators/ahoy/templates/database_store_initializer.rb.tt +10 -0
  31. data/lib/generators/ahoy/templates/{mongoid_event_model.rb → mongoid_event_model.rb.tt} +1 -1
  32. data/lib/generators/ahoy/templates/{mongoid_visit_model.rb → mongoid_visit_model.rb.tt} +9 -7
  33. data/vendor/assets/javascripts/ahoy.js +539 -552
  34. metadata +27 -204
  35. data/.github/ISSUE_TEMPLATE.md +0 -7
  36. data/.gitignore +0 -17
  37. data/Gemfile +0 -6
  38. data/Rakefile +0 -9
  39. data/ahoy_matey.gemspec +0 -36
  40. data/docs/Ahoy-2-Upgrade.md +0 -147
  41. data/docs/Data-Store-Examples.md +0 -240
  42. data/lib/generators/ahoy/templates/active_record_event_model.rb +0 -10
  43. data/lib/generators/ahoy/templates/active_record_visit_model.rb +0 -6
  44. data/lib/generators/ahoy/templates/database_store_initializer.rb +0 -5
  45. data/test/query_methods/mongoid_test.rb +0 -23
  46. data/test/query_methods/mysql_json_test.rb +0 -18
  47. data/test/query_methods/mysql_text_test.rb +0 -19
  48. data/test/query_methods/postgresql_hstore_test.rb +0 -20
  49. data/test/query_methods/postgresql_json_test.rb +0 -18
  50. data/test/query_methods/postgresql_jsonb_test.rb +0 -19
  51. data/test/query_methods/postgresql_text_test.rb +0 -19
  52. data/test/test_helper.rb +0 -100
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 47cc04adfac18b2f14547b376a3465f601d59307
4
- data.tar.gz: 6e1638296155ceab46f9d105e52d7422259ebc63
2
+ SHA256:
3
+ metadata.gz: 51e11f3086c12a1418ea7436e291ca9d2f0c7e0aa3091c48c904d05b4be6a210
4
+ data.tar.gz: 5b5c6afc94c0db23f2f1616f6e9edc0ae95ff334e33704c26417705d06d04670
5
5
  SHA512:
6
- metadata.gz: 1f0a217bd790fff2b55e1e6395ea940079b2a457efc1328c61a054d6a3835f0d6fcb9c154eae7f3496f8a79559282cc3d9b1eefb2db4ce651d74d6c14dce536a
7
- data.tar.gz: 6789de07f914f49b05f72b4b5517935571368be2e43987421e170dd8da838d78a1fa48e1d878424a9800f53ea779b5dcd8b3523432977f7aec4a29e296941a41
6
+ metadata.gz: fd75680d3d04b2383c30b19848f88fcb838f1498e8819d2d758aec6443e85bfb2f73a421da968cb54628097631c777ac1f95dd1ca4bae6d6b22d748a44dcb84d
7
+ data.tar.gz: 2d336bd12312cddf4b76f213b1f7f84b1fc2f0b67302e75096d1eb21013982f532064b31894ba217f7ccbafdbaf5eb4c691a3a86350b8abf1449374f66015909
data/CHANGELOG.md CHANGED
@@ -1,4 +1,79 @@
1
- ## 2.0.0
1
+ ## 3.2.0 (2021-03-01)
2
+
3
+ - Disabled geocoding by default for new installations
4
+ - Fixed deprecation warning with Active Record 6.1
5
+
6
+ ## 3.1.0 (2020-12-04)
7
+
8
+ - Added `instance` method
9
+ - Added `request` argument to `user_method`
10
+ - Updated Ahoy.js to 0.3.8
11
+ - Removed `exclude_method` call when geocoding
12
+
13
+ ## 3.0.5 (2020-09-09)
14
+
15
+ - Added `group_prop` method
16
+ - Use `datetime` type in migration
17
+
18
+ ## 3.0.4 (2020-06-07)
19
+
20
+ - Updated Ahoy.js to 0.3.6
21
+
22
+ ## 3.0.3 (2020-04-17)
23
+
24
+ - Updated Ahoy.js to 0.3.5
25
+
26
+ ## 3.0.2 (2020-04-03)
27
+
28
+ - Added `cookie_options`
29
+
30
+ ## 3.0.1 (2019-09-21)
31
+
32
+ - Made `Ahoy::Tracker` work outside of requests
33
+ - Fixed storage of `false` values with customized store
34
+ - Fixed error with `user_method` and `Rails::InfoController`
35
+ - Gracefully handle `ActionDispatch::RemoteIp::IpSpoofAttackError`
36
+
37
+ ## 3.0.0 (2019-05-29)
38
+
39
+ - Made Device Detector the default user agent parser
40
+ - Made v2 the default bot detection version
41
+ - Removed a large number of dependencies
42
+ - Removed search keyword detection (most search engines today prevent this)
43
+ - Removed support for Rails < 5
44
+
45
+ ## 2.2.1 (2019-05-26)
46
+
47
+ - Updated Ahoy.js to 0.3.4
48
+ - Fixed v2 bot detection
49
+ - Added latitude and longitude to installation
50
+
51
+ ## 2.2.0 (2019-01-04)
52
+
53
+ - Added `amp_event` helper
54
+ - Improved bot detection for Device Detector
55
+
56
+ ## 2.1.0 (2018-05-18)
57
+
58
+ - Added option for IP masking
59
+ - Added option to use anonymity sets instead of cookies
60
+ - Added `user_agent_parser` option
61
+ - Fixed `visitable` for Rails 4.2
62
+ - Removed `search_keyword` from new installs
63
+
64
+ ## 2.0.2 (2018-03-14)
65
+
66
+ - Fixed error on duplicate records
67
+ - Fixed message when visit not found for geocoding
68
+ - Better compatibility with GeoLite2
69
+ - Better browser compatibility for Ahoy.js
70
+
71
+ ## 2.0.1 (2018-02-26)
72
+
73
+ - Added `Ahoy.server_side_visits = :when_needed` to automatically create visits server-side when needed for events and `visitable`
74
+ - Better handling of visit duration and expiration in JavaScript
75
+
76
+ ## 2.0.0 (2018-02-25)
2
77
 
3
78
  - Removed dependency on jQuery
4
79
  - Use `navigator.sendBeacon` by default in supported browsers
@@ -20,58 +95,58 @@ Breaking changes
20
95
  - Removed most built-in stores
21
96
  - Removed support for Rails < 4.2
22
97
 
23
- ## 1.6.1
98
+ ## 1.6.1 (2018-02-02)
24
99
 
25
100
  - Added `gin` index on properties for events
26
101
  - Fixed `visitable` options when name not provided
27
102
 
28
- ## 1.6.0
103
+ ## 1.6.0 (2017-05-01)
29
104
 
30
105
  - Added support for Rails 5.1
31
106
 
32
- ## 1.5.5
107
+ ## 1.5.5 (2017-03-23)
33
108
 
34
109
  - Added support for Rails API
35
110
  - Added NATS and NSQ stores
36
111
 
37
- ## 1.5.4
112
+ ## 1.5.4 (2017-01-22)
38
113
 
39
114
  - Fixed issue with duplicate events
40
115
  - Added support for PostGIS for `where_properties`
41
116
 
42
- ## 1.5.3
117
+ ## 1.5.3 (2016-10-31)
43
118
 
44
119
  - Fixed error with Rails 5 and Mongoid 6
45
120
  - Fixed regression with server not generating visit and visitor tokens
46
121
  - Accept UTM parameters as request parameters (for native apps)
47
122
 
48
- ## 1.5.2
123
+ ## 1.5.2 (2016-08-26)
49
124
 
50
125
  - Better support for Rails 5
51
126
 
52
- ## 1.5.1
127
+ ## 1.5.1 (2016-08-19)
53
128
 
54
129
  - Restored throttling after removing side effects
55
130
 
56
- ## 1.5.0
131
+ ## 1.5.0 (2016-08-19)
57
132
 
58
133
  - Removed throttling due to unintended side effects with its implementation
59
134
  - Ensure basic token requirements
60
135
  - Fixed visit recreation on cookie expiration
61
136
  - Fixed issue where `/ahoy/visits` is called indefinitely when `Ahoy.cookie_domain = :all`
62
137
 
63
- ## 1.4.2
138
+ ## 1.4.2 (2016-06-21)
64
139
 
65
140
  - Fixed issues with `where_properties`
66
141
 
67
- ## 1.4.1
142
+ ## 1.4.1 (2016-06-20)
68
143
 
69
144
  - Added `where_properties` method
70
145
  - Added Kafka store
71
146
  - Added `mount` option
72
147
  - Use less intrusive version of `safely`
73
148
 
74
- ## 1.4.0
149
+ ## 1.4.0 (2016-03-23)
75
150
 
76
151
  - Use `ActiveRecordTokenStore` by default (integer instead of uuid for id)
77
152
  - Detect database for `rails g ahoy:stores:active_record` for easier installation
@@ -79,55 +154,55 @@ Breaking changes
79
154
  - Fixed issue with log silencer
80
155
  - Use multi-column indexes on `ahoy_events` table creation
81
156
 
82
- ## 1.3.1
157
+ ## 1.3.1 (2016-03-22)
83
158
 
84
159
  - Raise errors in test environment
85
160
 
86
- ## 1.3.0
161
+ ## 1.3.0 (2016-03-06)
87
162
 
88
163
  - Added throttling
89
164
  - Added `max_content_length` and `max_events_per_request`
90
165
 
91
- ## 1.2.2
166
+ ## 1.2.2 (2016-03-05)
92
167
 
93
168
  - Fixed issue with latest version of `browser` gem
94
169
  - Added support for RabbitMQ
95
170
  - Added support for Amazon Kinesis Firehose
96
171
  - Fixed deprecation warnings in Rails 5
97
172
 
98
- ## 1.2.1
173
+ ## 1.2.1 (2015-08-14)
99
174
 
100
175
  - Fixed `SystemStackError: stack level too deep` when used with `activerecord-session_store`
101
176
 
102
- ## 1.2.0
177
+ ## 1.2.0 (2015-06-07)
103
178
 
104
179
  - Added support for PostgreSQL `jsonb` column type
105
180
  - Added Fluentd store
106
181
  - Added latitude, longitude, and postal_code to visits
107
182
  - Log exclusions
108
183
 
109
- ## 1.1.1
184
+ ## 1.1.1 (2015-01-05)
110
185
 
111
186
  - Better support for Authlogic
112
187
  - Added `screen_height` and `screen_width`
113
188
 
114
- ## 1.1.0
189
+ ## 1.1.0 (2014-11-02)
115
190
 
116
191
  - Added `geocode` option
117
192
  - Report errors to service by default
118
193
  - Fixed association mismatch
119
194
 
120
- ## 1.0.2
195
+ ## 1.0.2 (2014-07-10)
121
196
 
122
197
  - Fixed BSON for Mongoid 3
123
198
  - Fixed Doorkeeper integration
124
199
  - Fixed user tracking in overridden authenticate method
125
200
 
126
- ## 1.0.1
201
+ ## 1.0.1 (2014-06-27)
127
202
 
128
203
  - Fixed `visitable` outside of requests
129
204
 
130
- ## 1.0.0
205
+ ## 1.0.0 (2014-06-18)
131
206
 
132
207
  - Added support for any data store, and Mongoid out of the box
133
208
  - Added `track_visits_immediately` option
@@ -135,17 +210,17 @@ Breaking changes
135
210
  - Visits expire after inactivity, not fixed interval
136
211
  - Added `visit_duration` and `visitor_duration` options
137
212
 
138
- ## 0.3.2
213
+ ## 0.3.2 (2014-06-15)
139
214
 
140
215
  - Fixed bot exclusion for visits
141
216
  - Fixed user method
142
217
 
143
- ## 0.3.1
218
+ ## 0.3.1 (2014-06-12)
144
219
 
145
220
  - Fixed visitor cookies when set on server
146
221
  - Added `domain` option for server cookies
147
222
 
148
- ## 0.3.0
223
+ ## 0.3.0 (2014-06-11)
149
224
 
150
225
  - Added `current_visit_token` and `current_visitor_token` method
151
226
  - Switched to UUIDs
@@ -153,47 +228,47 @@ Breaking changes
153
228
  - Skip server-side bot events
154
229
  - Added `request` argument to `exclude_method`
155
230
 
156
- ## 0.2.2
231
+ ## 0.2.2 (2014-05-26)
157
232
 
158
233
  - Added `exclude_method` option
159
234
  - Added support for batch events
160
235
  - Fixed cookie encoding
161
236
  - Fixed `options` variable from being modified
162
237
 
163
- ## 0.2.1
238
+ ## 0.2.1 (2014-05-16)
164
239
 
165
240
  - Fixed IE 8 error
166
241
  - Added `track_bots` option
167
242
  - Added `$authenticate` event
168
243
 
169
- ## 0.2.0
244
+ ## 0.2.0 (2014-05-13)
170
245
 
171
246
  - Added event tracking (merged ahoy_events)
172
247
  - Added ahoy.js
173
248
 
174
- ## 0.1.8
249
+ ## 0.1.8 (2014-05-11)
175
250
 
176
251
  - Fixed bug with `user_type` set to `false` instead of `nil`
177
252
 
178
- ## 0.1.7
253
+ ## 0.1.7 (2014-05-11)
179
254
 
180
255
  - Made cookie functions public for ahoy_events
181
256
 
182
- ## 0.1.6
257
+ ## 0.1.6 (2014-05-07)
183
258
 
184
259
  - Better user agent parser
185
260
 
186
- ## 0.1.5
261
+ ## 0.1.5 (2014-05-01)
187
262
 
188
263
  - Added support for Doorkeeper
189
264
  - Added options to `visitable`
190
265
  - Added `landing_params` method
191
266
 
192
- ## 0.1.4
267
+ ## 0.1.4 (2014-04-27)
193
268
 
194
269
  - Added `ahoy.ready()` and `ahoy.log()` for events
195
270
 
196
- ## 0.1.3
271
+ ## 0.1.3 (2014-04-24)
197
272
 
198
273
  - Supports `current_user` from `ApplicationController`
199
274
  - Added `ahoy.reset()`
@@ -201,16 +276,16 @@ Breaking changes
201
276
  - Added experimental support for native apps
202
277
  - Prefer `ahoy` over `Ahoy`
203
278
 
204
- ## 0.1.2
279
+ ## 0.1.2 (2014-04-15)
205
280
 
206
281
  - Attach user on Devise sign up
207
282
  - Ability to specify visit model
208
283
 
209
- ## 0.1.1
284
+ ## 0.1.1 (2014-03-20)
210
285
 
211
286
  - Made most database columns optional
212
287
  - Performance hack for referer-parser
213
288
 
214
- ## 0.1.0
289
+ ## 0.1.0 (2014-03-19)
215
290
 
216
291
  - First major release
data/CONTRIBUTING.md CHANGED
@@ -2,17 +2,15 @@
2
2
 
3
3
  First, thanks for wanting to contribute. You’re awesome! :heart:
4
4
 
5
- ## Questions
5
+ ## Help
6
6
 
7
- Use [Stack Overflow](https://stackoverflow.com/) with the tag `ahoy`.
7
+ We’re not able to provide support through GitHub Issues. If you’re looking for help with your code, try posting on [Stack Overflow](https://stackoverflow.com/).
8
8
 
9
- ## Feature Requests
9
+ All features should be documented. If you don’t see a feature in the docs, assume it doesn’t exist.
10
10
 
11
- Create an issue. Start the title with `[Idea]`.
11
+ ## Bugs
12
12
 
13
- ## Issues
14
-
15
- Think you’ve discovered an issue?
13
+ Think you’ve discovered a bug?
16
14
 
17
15
  1. Search existing issues to see if it’s been reported.
18
16
  2. Try the `master` branch to make sure it hasn’t been fixed.
@@ -26,6 +24,10 @@ If the above steps don’t help, create an issue. Include:
26
24
  - Detailed steps to reproduce
27
25
  - Complete backtraces for exceptions
28
26
 
27
+ ## New Features
28
+
29
+ If you’d like to discuss a new feature, create an issue and start the title with `[Idea]`.
30
+
29
31
  ## Pull Requests
30
32
 
31
33
  Fork the project and create a pull request. A few tips:
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014-2018 Andrew Kane
1
+ Copyright (c) 2014-2020 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # Ahoy
2
2
 
3
- :fire: Simple, powerful analytics for Rails
3
+ :fire: Simple, powerful, first-party analytics for Rails
4
4
 
5
5
  Track visits and events in Ruby, JavaScript, and native apps. Data is stored in your database by default so you can easily combine it with other data.
6
6
 
7
- **Ahoy 2.0 was recently released!** See [how to upgrade](docs/Ahoy-2-Upgrade.md)
8
-
9
- :postbox: To track emails, check out [Ahoy Email](https://github.com/ankane/ahoy_email), and for A/B testing, check out [Field Test](https://github.com/ankane/field_test)
7
+ :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
10
8
 
11
9
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
12
10
 
11
+ [![Build Status](https://github.com/ankane/ahoy/workflows/build/badge.svg?branch=master)](https://github.com/ankane/ahoy/actions)
12
+
13
13
  ## Installation
14
14
 
15
15
  Add this line to your application’s Gemfile:
@@ -31,12 +31,12 @@ Restart your web server, open a page in your browser, and a visit will be create
31
31
  Track your first event from a controller with:
32
32
 
33
33
  ```ruby
34
- ahoy.track "My first event", {language: "Ruby"}
34
+ ahoy.track "My first event", language: "Ruby"
35
35
  ```
36
36
 
37
- ### JavaScript & Native Apps
37
+ ### JavaScript, Native Apps, & AMP
38
38
 
39
- First, enable the API in `config/initializers/ahoy.rb`:
39
+ Enable the API in `config/initializers/ahoy.rb`:
40
40
 
41
41
  ```ruby
42
42
  Ahoy.api = true
@@ -44,19 +44,43 @@ Ahoy.api = true
44
44
 
45
45
  And restart your web server.
46
46
 
47
- For JavaScript, add to `app/assets/javascripts/application.js`:
47
+ ### JavaScript
48
+
49
+ For Rails 6 / Webpacker, run:
50
+
51
+ ```sh
52
+ yarn add ahoy.js
53
+ ```
54
+
55
+ And add to `app/javascript/packs/application.js`:
56
+
57
+ ```javascript
58
+ import ahoy from "ahoy.js";
59
+ ```
60
+
61
+ For Rails 5 / Sprockets, add to `app/assets/javascripts/application.js`:
48
62
 
49
63
  ```javascript
50
64
  //= require ahoy
51
65
  ```
52
66
 
53
- And track an event with:
67
+ Track an event with:
54
68
 
55
69
  ```javascript
56
70
  ahoy.track("My second event", {language: "JavaScript"});
57
71
  ```
58
72
 
59
- For native apps, see the [API spec](#api-spec).
73
+ ### Native Apps
74
+
75
+ Check out [Ahoy iOS](https://github.com/namolnad/ahoy-ios) and [Ahoy Android](https://github.com/instacart/ahoy-android).
76
+
77
+ ### GDPR Compliance
78
+
79
+ Ahoy provides a number of options to help with GDPR compliance. See the [GDPR section](#gdpr-compliance-1) for more info.
80
+
81
+ ### Geocoding Setup
82
+
83
+ To enable geocoding, see the [Geocoding section](#geocoding).
60
84
 
61
85
  ## How It Works
62
86
 
@@ -64,9 +88,9 @@ For native apps, see the [API spec](#api-spec).
64
88
 
65
89
  When someone visits your website, Ahoy creates a visit with lots of useful information.
66
90
 
67
- - **traffic source** - referrer, referring domain, landing page, search keyword
68
- - **location** - country, region, and city
69
- - **technology** - browser, OS, and device type
91
+ - **traffic source** - referrer, referring domain, landing page
92
+ - **location** - country, region, city, latitude, longitude
93
+ - **technology** - browser, OS, device type
70
94
  - **utm parameters** - source, medium, term, content, campaign
71
95
 
72
96
  Use the `current_visit` method to access it.
@@ -77,33 +101,21 @@ Prevent certain Rails actions from creating visits with:
77
101
  skip_before_action :track_ahoy_visit
78
102
  ```
79
103
 
80
- This is typically useful for APIs.
81
-
82
- You can also defer visit tracking to JavaScript (Ahoy 1.0 behavior) with:
104
+ This is typically useful for APIs. If your entire Rails app is an API, you can use:
83
105
 
84
106
  ```ruby
85
- Ahoy.server_side_visits = false
107
+ Ahoy.api_only = true
86
108
  ```
87
109
 
88
- ### Events
110
+ You can also defer visit tracking to JavaScript. This is useful for preventing bots (that aren’t detected by their user agent) and users with cookies disabled from creating a new visit on each request. `:when_needed` will create visits server-side only when needed by events, and `false` will disable server-side creation completely, discarding events without a visit.
89
111
 
90
- Each event has a `name` and `properties`.
91
-
92
- There are three ways to track events.
93
-
94
- #### JavaScript
95
-
96
- ```javascript
97
- ahoy.track("Viewed book", {title: "The World is Flat"});
112
+ ```ruby
113
+ Ahoy.server_side_visits = :when_needed
98
114
  ```
99
115
 
100
- or track events automatically with:
101
-
102
- ```javascript
103
- ahoy.trackAll();
104
- ```
116
+ ### Events
105
117
 
106
- See [Ahoy.js](https://github.com/ankane/ahoy.js) for a complete list of features.
118
+ Each event has a `name` and `properties`. There are several ways to track events.
107
119
 
108
120
  #### Ruby
109
121
 
@@ -111,7 +123,7 @@ See [Ahoy.js](https://github.com/ankane/ahoy.js) for a complete list of features
111
123
  ahoy.track "Viewed book", title: "Hot, Flat, and Crowded"
112
124
  ```
113
125
 
114
- or track actions automatically with:
126
+ Track actions automatically with:
115
127
 
116
128
  ```ruby
117
129
  class ApplicationController < ActionController::Base
@@ -120,51 +132,74 @@ class ApplicationController < ActionController::Base
120
132
  protected
121
133
 
122
134
  def track_action
123
- ahoy.track "Viewed action", request.path_parameters
135
+ ahoy.track "Ran action", request.path_parameters
124
136
  end
125
137
  end
126
138
  ```
127
139
 
128
- #### Native Apps
140
+ #### JavaScript
129
141
 
130
- See the [API spec](#api-spec).
142
+ ```javascript
143
+ ahoy.track("Viewed book", {title: "The World is Flat"});
144
+ ```
131
145
 
132
- ### Associated Models
146
+ Track events automatically with:
133
147
 
134
- Say we want to associate orders with visits. Ahoy can do this automatically.
148
+ ```javascript
149
+ ahoy.trackAll();
150
+ ```
135
151
 
136
- First, generate a migration and add a `visit_id` column (not needed for Mongoid).
152
+ See [Ahoy.js](https://github.com/ankane/ahoy.js) for a complete list of features.
137
153
 
138
- ```ruby
139
- class AddVisitIdToOrders < ActiveRecord::Migration[5.1]
140
- def change
141
- add_column :orders, :visit_id, :bigint
142
- end
143
- end
154
+ #### Native Apps
155
+
156
+ See the docs for [Ahoy iOS](https://github.com/namolnad/ahoy-ios) and [Ahoy Android](https://github.com/instacart/ahoy-android).
157
+
158
+ #### AMP
159
+
160
+ ```erb
161
+ <head>
162
+ <script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>
163
+ </head>
164
+ <body>
165
+ <%= amp_event "Viewed article", title: "Analytics with Rails" %>
166
+ </body>
144
167
  ```
145
168
 
146
- Then, add `visitable` to the model.
169
+ ### Associated Models
170
+
171
+ Say we want to associate orders with visits. Just add `visitable` to the model.
147
172
 
148
173
  ```ruby
149
174
  class Order < ApplicationRecord
150
- visitable
175
+ visitable :ahoy_visit
151
176
  end
152
177
  ```
153
178
 
154
- When a visitor places an order, the `visit_id` column is automatically set :tada:
179
+ When a visitor places an order, the `ahoy_visit_id` column is automatically set :tada:
155
180
 
156
181
  See where orders are coming from with simple joins:
157
182
 
158
183
  ```ruby
159
- Order.joins(:visit).group("referring_domain").count
160
- Order.joins(:visit).group("city").count
161
- Order.joins(:visit).group("device_type").count
184
+ Order.joins(:ahoy_visit).group("referring_domain").count
185
+ Order.joins(:ahoy_visit).group("city").count
186
+ Order.joins(:ahoy_visit).group("device_type").count
187
+ ```
188
+
189
+ Here’s what the migration to add the `ahoy_visit_id` column should look like:
190
+
191
+ ```ruby
192
+ class AddVisitIdToOrders < ActiveRecord::Migration[6.0]
193
+ def change
194
+ add_column :orders, :ahoy_visit_id, :bigint
195
+ end
196
+ end
162
197
  ```
163
198
 
164
- Customize the column and class name with:
199
+ Customize the column with:
165
200
 
166
201
  ```ruby
167
- visitable :sign_up_visit, class_name: "Visit"
202
+ visitable :sign_up_visit
168
203
  ```
169
204
 
170
205
  ### Users
@@ -205,7 +240,7 @@ or use a proc
205
240
  Ahoy.user_method = ->(controller) { controller.true_user }
206
241
  ```
207
242
 
208
- ### Doorkeeper
243
+ #### Doorkeeper
209
244
 
210
245
  To attach the user with [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper), be sure you have a `current_resource_owner` method in `ApplicationController`.
211
246
 
@@ -219,9 +254,31 @@ class ApplicationController < ActionController::Base
219
254
  end
220
255
  ```
221
256
 
257
+ #### Knock
258
+
259
+ To attach the user with [Knock](https://github.com/nsarno/knock), either include `Knock::Authenticable`in `ApplicationController`:
260
+
261
+ ```ruby
262
+ class ApplicationController < ActionController::API
263
+ include Knock::Authenticable
264
+ end
265
+ ```
266
+
267
+ Or include it in Ahoy:
268
+
269
+ ```ruby
270
+ Ahoy::BaseController.include Knock::Authenticable
271
+ ```
272
+
273
+ And use:
274
+
275
+ ```ruby
276
+ Ahoy.user_method = ->(controller) { controller.send(:authenticate_entity, "user") }
277
+ ```
278
+
222
279
  ### Exclusions
223
280
 
224
- Bots are excluded from tracking by default. To enable, use:
281
+ Bots are excluded from tracking by default. To include them, use:
225
282
 
226
283
  ```ruby
227
284
  Ahoy.track_bots = true
@@ -243,7 +300,7 @@ By default, a new visit is created after 4 hours of inactivity. Change this with
243
300
  Ahoy.visit_duration = 30.minutes
244
301
  ```
245
302
 
246
- ### Multiple Subdomains
303
+ ### Cookies
247
304
 
248
305
  To track visits across multiple subdomains, use:
249
306
 
@@ -251,20 +308,65 @@ To track visits across multiple subdomains, use:
251
308
  Ahoy.cookie_domain = :all
252
309
  ```
253
310
 
311
+ Set other [cookie options](https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html) with:
312
+
313
+ ```ruby
314
+ Ahoy.cookie_options = {same_site: :lax}
315
+ ```
316
+
254
317
  ### Geocoding
255
318
 
256
- Disable geocoding with:
319
+ Ahoy uses [Geocoder](https://github.com/alexreisner/geocoder) for geocoding. We recommend configuring [local geocoding](#local-geocoding) so IP addresses are not sent to a 3rd party service. If you do use a 3rd party service, be sure to add it to your GDPR subprocessor list. If Ahoy is configured to [mask ips](#ip-masking), the masked IP is used (this increases privacy but can reduce accuracy).
320
+
321
+ To enable geocoding, update `config/initializers/ahoy.rb`:
257
322
 
258
323
  ```ruby
259
- Ahoy.geocode = false
324
+ Ahoy.geocode = true
260
325
  ```
261
326
 
262
- Change the job queue with:
327
+ Geocoding is performed in a background job so it doesn’t slow down web requests. The default job queue is `:ahoy`. Change this with:
263
328
 
264
329
  ```ruby
265
330
  Ahoy.job_queue = :low_priority
266
331
  ```
267
332
 
333
+ ### Local Geocoding
334
+
335
+ For privacy and performance, we recommend geocoding locally. Add this line to your application’s Gemfile:
336
+
337
+ ```ruby
338
+ gem 'maxminddb'
339
+ ```
340
+
341
+ For city-level geocoding, download the [GeoLite2 City database](https://dev.maxmind.com/geoip/geoip2/geolite2/) and create `config/initializers/geocoder.rb` with:
342
+
343
+ ```ruby
344
+ Geocoder.configure(
345
+ ip_lookup: :geoip2,
346
+ geoip2: {
347
+ file: "path/to/GeoLite2-City.mmdb"
348
+ }
349
+ )
350
+ ```
351
+
352
+ For country-level geocoding, install the `geoip-database` package. It’s preinstalled on Heroku. For Ubuntu, use:
353
+
354
+ ```sh
355
+ sudo apt-get install geoip-database
356
+ ```
357
+
358
+ And create `config/initializers/geocoder.rb` with:
359
+
360
+ ```ruby
361
+ Geocoder.configure(
362
+ ip_lookup: :maxmind_local,
363
+ maxmind_local: {
364
+ file: "/usr/share/GeoIP/GeoIP.dat",
365
+ package: :country
366
+ }
367
+ )
368
+ ```
369
+
268
370
  ### Token Generation
269
371
 
270
372
  Ahoy uses random UUIDs for visit and visitor tokens by default, but you can use your own generator like [Druuid](https://github.com/recurly/druuid).
@@ -295,6 +397,94 @@ Exceptions are rescued so analytics do not break your app. Ahoy uses [Safely](ht
295
397
  Safely.report_exception_method = ->(e) { Rollbar.error(e) }
296
398
  ```
297
399
 
400
+ ## GDPR Compliance
401
+
402
+ Ahoy provides a number of options to help with [GDPR compliance](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation).
403
+
404
+ Update `config/initializers/ahoy.rb` with:
405
+
406
+ ```ruby
407
+ class Ahoy::Store < Ahoy::DatabaseStore
408
+ def authenticate(data)
409
+ # disables automatic linking of visits and users
410
+ end
411
+ end
412
+
413
+ Ahoy.mask_ips = true
414
+ Ahoy.cookies = false
415
+ ```
416
+
417
+ This:
418
+
419
+ - Masks IP addresses
420
+ - Switches from cookies to anonymity sets
421
+ - Disables automatic linking of visits and users
422
+
423
+ If you use JavaScript tracking, also set:
424
+
425
+ ```javascript
426
+ ahoy.configure({cookies: false});
427
+ ```
428
+
429
+ ### IP Masking
430
+
431
+ Ahoy can mask IPs with the same approach [Google Analytics uses for IP anonymization](https://support.google.com/analytics/answer/2763052). This means:
432
+
433
+ - For IPv4, the last octet is set to 0 (`8.8.4.4` becomes `8.8.4.0`)
434
+ - For IPv6, the last 80 bits are set to zeros (`2001:4860:4860:0:0:0:0:8844` becomes `2001:4860:4860::`)
435
+
436
+ ```ruby
437
+ Ahoy.mask_ips = true
438
+ ```
439
+
440
+ IPs are masked before geolocation is performed.
441
+
442
+ To mask previously collected IPs, use:
443
+
444
+ ```ruby
445
+ Ahoy::Visit.find_each do |visit|
446
+ visit.update_column :ip, Ahoy.mask_ip(visit.ip)
447
+ end
448
+ ```
449
+
450
+ ### Anonymity Sets & Cookies
451
+
452
+ Ahoy can switch from cookies to [anonymity sets](https://privacypatterns.org/patterns/Anonymity-set). Instead of cookies, visitors with the same IP mask and user agent are grouped together in an anonymity set.
453
+
454
+ ```ruby
455
+ Ahoy.cookies = false
456
+ ```
457
+
458
+ Previously set cookies are automatically deleted.
459
+
460
+ ## Data Retention
461
+
462
+ Data should only be retained for as long as it’s needed. Delete older data with:
463
+
464
+ ```ruby
465
+ Ahoy::Visit.where("started_at < ?", 2.years.ago).find_in_batches do |visits|
466
+ visit_ids = visits.map(&:id)
467
+ Ahoy::Event.where(visit_id: visit_ids).delete_all
468
+ Ahoy::Visit.where(id: visit_ids).delete_all
469
+ end
470
+ ```
471
+
472
+ You can use [Rollup](https://github.com/ankane/rollup) to aggregate important data before you do.
473
+
474
+ ```ruby
475
+ Ahoy::Visit.rollup("Visits", interval: "hour")
476
+ ```
477
+
478
+ Delete data for a specific user with:
479
+
480
+ ```ruby
481
+ user_id = 123
482
+ visit_ids = Ahoy::Visit.where(user_id: user_id).pluck(:id)
483
+ Ahoy::Event.where(visit_id: visit_ids).delete_all
484
+ Ahoy::Visit.where(id: visit_ids).delete_all
485
+ Ahoy::Event.where(user_id: user_id).delete_all
486
+ ```
487
+
298
488
  ## Development
299
489
 
300
490
  Ahoy is built with developers in mind. You can run the following code in your browser’s console.
@@ -369,6 +559,23 @@ end
369
559
 
370
560
  Two useful methods you can use are `request` and `controller`.
371
561
 
562
+ You can pass additional visit data from JavaScript with:
563
+
564
+ ```javascript
565
+ ahoy.configure({visitParams: {referral_code: 123}});
566
+ ```
567
+
568
+ And use:
569
+
570
+ ```ruby
571
+ class Ahoy::Store < Ahoy::DatabaseStore
572
+ def track_visit(data)
573
+ data[:referral_code] = request.parameters[:referral_code]
574
+ super(data)
575
+ end
576
+ end
577
+ ```
578
+
372
579
  ### Use Different Models
373
580
 
374
581
  ```ruby
@@ -395,7 +602,7 @@ Ahoy::Visit.group(:country).count
395
602
  Ahoy::Visit.group(:referring_domain).count
396
603
  ```
397
604
 
398
- [Chartkick](http://chartkick.com/) and [Groupdate](https://github.com/ankane/groupdate) make it easy to visualize the data.
605
+ [Chartkick](https://www.chartkick.com/) and [Groupdate](https://github.com/ankane/groupdate) make it easy to visualize the data.
399
606
 
400
607
  ```erb
401
608
  <%= line_chart Ahoy::Visit.group_by_day(:started_at).count %>
@@ -403,7 +610,7 @@ Ahoy::Visit.group(:referring_domain).count
403
610
 
404
611
  ### Querying Events
405
612
 
406
- Ahoy provides two methods on the event model to make querying easier.
613
+ Ahoy provides a few methods on the event model to make querying easier.
407
614
 
408
615
  To query on both name and properties, you can use:
409
616
 
@@ -414,9 +621,17 @@ Ahoy::Event.where_event("Viewed product", product_id: 123).count
414
621
  Or just query properties with:
415
622
 
416
623
  ```ruby
417
- Ahoy::Event.where_props(product_id: 123).count
624
+ Ahoy::Event.where_props(product_id: 123, category: "Books").count
418
625
  ```
419
626
 
627
+ Group by properties with:
628
+
629
+ ```ruby
630
+ Ahoy::Event.group_prop(:product_id, :category).count
631
+ ```
632
+
633
+ Note: MySQL and MariaDB always return string keys (include `"null"` for `nil`) for `group_prop`.
634
+
420
635
  ### Funnels
421
636
 
422
637
  It’s easy to create funnels.
@@ -429,6 +644,29 @@ viewed_checkout_ids = Ahoy::Event.where(user_id: added_item_ids, name: "Viewed c
429
644
 
430
645
  The same approach also works with visitor tokens.
431
646
 
647
+ ### Rollups
648
+
649
+ Improve query performance by pre-aggregating data with [Rollup](https://github.com/ankane/rollup).
650
+
651
+ ```ruby
652
+ Ahoy::Event.where(name: "Viewed store").rollup("Store views")
653
+ ```
654
+
655
+ This is only needed if you have a lot of data.
656
+
657
+ ### Forecasting
658
+
659
+ To forecast future visits and events, check out [Prophet](https://github.com/ankane/prophet).
660
+
661
+ ```ruby
662
+ daily_visits = Ahoy::Visit.group_by_day(:started_at).count # uses Groupdate
663
+ Prophet.forecast(daily_visits)
664
+ ```
665
+
666
+ ### Recommendations
667
+
668
+ To make recommendations based on events, check out [Disco](https://github.com/ankane/disco#ahoy).
669
+
432
670
  ## Tutorials
433
671
 
434
672
  - [Tracking Metrics with Ahoy and Blazer](https://gorails.com/episodes/internal-metrics-with-ahoy-and-blazer)
@@ -437,7 +675,7 @@ The same approach also works with visitor tokens.
437
675
 
438
676
  ### Visits
439
677
 
440
- Generate visit and visitor tokens as [UUIDs](http://en.wikipedia.org/wiki/Universally_unique_identifier), and include these values in the `Ahoy-Visit` and `Ahoy-Visitor` headers with all requests.
678
+ Generate visit and visitor tokens as [UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier), and include these values in the `Ahoy-Visit` and `Ahoy-Visitor` headers with all requests.
441
679
 
442
680
  Send a `POST` request to `/ahoy/visits` with `Content-Type: application/json` and a body like:
443
681
 
@@ -474,6 +712,65 @@ Send a `POST` request to `/ahoy/events` with `Content-Type: application/json` an
474
712
  }
475
713
  ```
476
714
 
715
+ ## Upgrading
716
+
717
+ ### 3.0
718
+
719
+ If you installed Ahoy before 2.1 and want to keep legacy user agent parsing and bot detection, add to your Gemfile:
720
+
721
+ ```ruby
722
+ gem "browser", "~> 2.0"
723
+ gem "user_agent_parser"
724
+ ```
725
+
726
+ And add to `config/initializers/ahoy.rb`:
727
+
728
+ ```ruby
729
+ Ahoy.user_agent_parser = :legacy
730
+ ```
731
+
732
+ ### 2.2
733
+
734
+ 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`:
735
+
736
+ ```ruby
737
+ Ahoy.bot_detection_version = 2
738
+ ```
739
+
740
+ ### 2.1
741
+
742
+ 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`:
743
+
744
+ ```ruby
745
+ Ahoy.user_agent_parser = :device_detector
746
+ ```
747
+
748
+ Backfill existing records with:
749
+
750
+ ```ruby
751
+ Ahoy::Visit.find_each do |visit|
752
+ client = DeviceDetector.new(visit.user_agent)
753
+ device_type =
754
+ case client.device_type
755
+ when "smartphone"
756
+ "Mobile"
757
+ when "tv"
758
+ "TV"
759
+ else
760
+ client.device_type.try(:titleize)
761
+ end
762
+
763
+ visit.browser = client.name
764
+ visit.os = client.os_name
765
+ visit.device_type = device_type
766
+ visit.save(validate: false) if visit.changed?
767
+ end
768
+ ```
769
+
770
+ ### 2.0
771
+
772
+ See the [upgrade guide](docs/Ahoy-2-Upgrade.md)
773
+
477
774
  ## History
478
775
 
479
776
  View the [changelog](https://github.com/ankane/ahoy/blob/master/CHANGELOG.md)
@@ -486,3 +783,20 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
486
783
  - Fix bugs and [submit pull requests](https://github.com/ankane/ahoy/pulls)
487
784
  - Write, clarify, or fix documentation
488
785
  - Suggest or add new features
786
+
787
+ To get started with development:
788
+
789
+ ```sh
790
+ git clone https://github.com/ankane/ahoy.git
791
+ cd ahoy
792
+ bundle install
793
+ bundle exec rake test
794
+ ```
795
+
796
+ To test query methods, start PostgreSQL, MySQL, and MongoDB and use:
797
+
798
+ ```sh
799
+ createdb ahoy_test
800
+ mysqladmin create ahoy_test
801
+ bundle exec rake test:query_methods
802
+ ```