ahoy_matey 5.1.0 → 5.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 +4 -4
- data/CHANGELOG.md +47 -0
- data/LICENSE.txt +1 -1
- data/README.md +8 -34
- data/app/controllers/ahoy/base_controller.rb +2 -1
- data/app/controllers/ahoy/events_controller.rb +13 -2
- data/lib/ahoy/engine.rb +1 -1
- data/lib/ahoy/query_methods.rb +11 -11
- data/lib/ahoy/tracker.rb +13 -6
- data/lib/ahoy/version.rb +1 -1
- data/lib/generators/ahoy/activerecord_generator.rb +0 -4
- data/lib/generators/ahoy/install_generator.rb +5 -5
- data/lib/generators/ahoy/templates/active_record_event_model.rb.tt +1 -1
- data/vendor/assets/javascripts/ahoy.js +2 -2
- metadata +20 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 44d4e5d43d7fad25db6c27bc9bdfcefa0a4226be502b312a53aa6ad845f17d4d
|
|
4
|
+
data.tar.gz: 51798d1dd69a5f42f64dc18d3195d8ad80fe85568c78d839c470d708bfc6b18a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 78fceba09807aa17acf80c2c6d61d10b4eb9f8318780650f07714d0307864c417003084de42a6f856065e46cf977743aab0e5008f308924c741e4ecc786db3c7
|
|
7
|
+
data.tar.gz: e0603191b7a45e2835617b7b32c6d59aaa00f04dd641683a5fd0b8a4b841422819d51b124b93f9f0b6301dbbdc80a3dabdf1928fc21c0119930002a07c07d7cf
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
## 5.5.0 (2026-04-08)
|
|
2
|
+
|
|
3
|
+
- Fixed error with `Ahoy::Tracker` outside of requests
|
|
4
|
+
- Dropped support for Ruby < 3.3 and Rails < 7.2
|
|
5
|
+
|
|
6
|
+
## 5.4.2 (2026-03-31)
|
|
7
|
+
|
|
8
|
+
- Fixed cookie deletion with `cookie_domain` and `cookie_options` options
|
|
9
|
+
- Updated Ahoy.js to 0.4.5
|
|
10
|
+
|
|
11
|
+
## 5.4.1 (2025-09-30)
|
|
12
|
+
|
|
13
|
+
- Fixed deprecation warning with Rack 3.1+
|
|
14
|
+
|
|
15
|
+
## 5.4.0 (2025-05-04)
|
|
16
|
+
|
|
17
|
+
- Dropped support for Ruby < 3.2 and Rails < 7.1
|
|
18
|
+
|
|
19
|
+
## 5.3.0 (2025-02-01)
|
|
20
|
+
|
|
21
|
+
- Dropped support for Ruby < 3.1 and Rails < 7
|
|
22
|
+
- Dropped support for Mongoid < 8
|
|
23
|
+
|
|
24
|
+
## 5.2.1 (2024-10-07)
|
|
25
|
+
|
|
26
|
+
- Fixed connection leasing for Active Record 7.2+
|
|
27
|
+
|
|
28
|
+
## 5.2.0 (2024-09-04)
|
|
29
|
+
|
|
30
|
+
- Improved error handling for invalid API parameters
|
|
31
|
+
|
|
1
32
|
## 5.1.0 (2024-03-26)
|
|
2
33
|
|
|
3
34
|
- Added support for Trilogy
|
|
@@ -354,3 +385,19 @@ Breaking changes
|
|
|
354
385
|
## 0.1.0 (2014-03-19)
|
|
355
386
|
|
|
356
387
|
- First major release
|
|
388
|
+
|
|
389
|
+
## 0.0.4 (2014-03-01)
|
|
390
|
+
|
|
391
|
+
- Added UTM parameters
|
|
392
|
+
|
|
393
|
+
## 0.0.3 (2014-02-26)
|
|
394
|
+
|
|
395
|
+
- Renamed `ahoy_visit` method to `current_visit`
|
|
396
|
+
|
|
397
|
+
## 0.0.2 (2014-02-26)
|
|
398
|
+
|
|
399
|
+
- Added `ahoy_visit` method to controllers
|
|
400
|
+
|
|
401
|
+
## 0.0.1 (2014-02-26)
|
|
402
|
+
|
|
403
|
+
- First release
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -4,8 +4,6 @@
|
|
|
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 5.0 was recently released** - see [how to upgrade](#upgrading)
|
|
8
|
-
|
|
9
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)
|
|
@@ -48,7 +46,7 @@ And restart your web server.
|
|
|
48
46
|
|
|
49
47
|
### JavaScript
|
|
50
48
|
|
|
51
|
-
For Importmap (Rails
|
|
49
|
+
For Importmap (Rails default), add to `config/importmap.rb`:
|
|
52
50
|
|
|
53
51
|
```ruby
|
|
54
52
|
pin "ahoy", to: "ahoy.js"
|
|
@@ -60,13 +58,15 @@ And add to `app/javascript/application.js`:
|
|
|
60
58
|
import "ahoy"
|
|
61
59
|
```
|
|
62
60
|
|
|
63
|
-
For
|
|
61
|
+
For Bun, esbuild, rollup.js, or Webpack, run:
|
|
64
62
|
|
|
65
63
|
```sh
|
|
64
|
+
bun add ahoy.js
|
|
65
|
+
# or
|
|
66
66
|
yarn add ahoy.js
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
And add to `app/javascript/
|
|
69
|
+
And add to `app/javascript/application.js`:
|
|
70
70
|
|
|
71
71
|
```javascript
|
|
72
72
|
import ahoy from "ahoy.js"
|
|
@@ -197,7 +197,7 @@ Order.joins(:ahoy_visit).group("device_type").count
|
|
|
197
197
|
Here’s what the migration to add the `ahoy_visit_id` column should look like:
|
|
198
198
|
|
|
199
199
|
```ruby
|
|
200
|
-
class AddAhoyVisitToOrders < ActiveRecord::Migration[
|
|
200
|
+
class AddAhoyVisitToOrders < ActiveRecord::Migration[8.1]
|
|
201
201
|
def change
|
|
202
202
|
add_reference :orders, :ahoy_visit
|
|
203
203
|
end
|
|
@@ -490,7 +490,7 @@ Ahoy can switch from cookies to [anonymity sets](https://privacypatterns.org/pat
|
|
|
490
490
|
Ahoy.cookies = :none
|
|
491
491
|
```
|
|
492
492
|
|
|
493
|
-
Note: If Ahoy was installed before v5, [add an index](#50) before making this change.
|
|
493
|
+
Note: If Ahoy was installed before v5, [add an index](https://github.com/ankane/ahoy/tree/v5.0.0?tab=readme-ov-file#50) before making this change.
|
|
494
494
|
|
|
495
495
|
Previously set cookies are automatically deleted. If you use JavaScript tracking, also set:
|
|
496
496
|
|
|
@@ -765,38 +765,12 @@ Send a `POST` request to `/ahoy/events` with `Content-Type: application/json` an
|
|
|
765
765
|
"properties": {
|
|
766
766
|
"item_id": 123
|
|
767
767
|
},
|
|
768
|
-
"time": "
|
|
768
|
+
"time": "2025-01-01T00:00:00-07:00"
|
|
769
769
|
}
|
|
770
770
|
]
|
|
771
771
|
}
|
|
772
772
|
```
|
|
773
773
|
|
|
774
|
-
## Upgrading
|
|
775
|
-
|
|
776
|
-
### 5.0
|
|
777
|
-
|
|
778
|
-
Visits now expire with anonymity sets. If using `Ahoy.cookies = false`, a new index is needed.
|
|
779
|
-
|
|
780
|
-
For Active Record, create a migration with:
|
|
781
|
-
|
|
782
|
-
```ruby
|
|
783
|
-
add_index :ahoy_visits, [:visitor_token, :started_at]
|
|
784
|
-
```
|
|
785
|
-
|
|
786
|
-
For Mongoid, set:
|
|
787
|
-
|
|
788
|
-
```ruby
|
|
789
|
-
class Ahoy::Visit
|
|
790
|
-
index({visitor_token: 1, started_at: 1})
|
|
791
|
-
end
|
|
792
|
-
```
|
|
793
|
-
|
|
794
|
-
Create the index before upgrading, and set:
|
|
795
|
-
|
|
796
|
-
```ruby
|
|
797
|
-
Ahoy.cookies = :none
|
|
798
|
-
```
|
|
799
|
-
|
|
800
774
|
## History
|
|
801
775
|
|
|
802
776
|
View the [changelog](https://github.com/ankane/ahoy/blob/master/CHANGELOG.md)
|
|
@@ -36,7 +36,8 @@ module Ahoy
|
|
|
36
36
|
def verify_request_size
|
|
37
37
|
if request.content_length > Ahoy.max_content_length
|
|
38
38
|
logger.info "[ahoy] Payload too large"
|
|
39
|
-
|
|
39
|
+
status = Rack::RELEASE.to_f >= 3.1 ? :content_too_large : :payload_too_large
|
|
40
|
+
render plain: "Payload too large\n", status: status
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
43
|
end
|
|
@@ -17,12 +17,23 @@ module Ahoy
|
|
|
17
17
|
begin
|
|
18
18
|
ActiveSupport::JSON.decode(data)
|
|
19
19
|
rescue ActiveSupport::JSON.parse_error
|
|
20
|
-
#
|
|
20
|
+
# TODO change to nil in Ahoy 6
|
|
21
21
|
[]
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
max_events_per_request = Ahoy.max_events_per_request
|
|
26
|
+
|
|
27
|
+
# check before creating any events
|
|
28
|
+
unless events.is_a?(Array) && events.first(max_events_per_request).all? { |v| v.is_a?(Hash) }
|
|
29
|
+
logger.info "[ahoy] Invalid parameters"
|
|
30
|
+
# :unprocessable_entity is probably more correct
|
|
31
|
+
# but keep consistent with missing parameters for now
|
|
32
|
+
render plain: "Invalid parameters\n", status: :bad_request
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
events.first(max_events_per_request).each do |event|
|
|
26
37
|
time = Time.zone.parse(event["time"]) rescue nil
|
|
27
38
|
|
|
28
39
|
# timestamp is deprecated
|
data/lib/ahoy/engine.rb
CHANGED
data/lib/ahoy/query_methods.rb
CHANGED
|
@@ -10,13 +10,13 @@ module Ahoy
|
|
|
10
10
|
def where_props(properties)
|
|
11
11
|
return all if properties.empty?
|
|
12
12
|
|
|
13
|
-
adapter_name = respond_to?(:
|
|
13
|
+
adapter_name = respond_to?(:connection_db_config) ? connection_db_config.adapter.to_s : "mongoid"
|
|
14
14
|
case adapter_name
|
|
15
15
|
when "mongoid"
|
|
16
16
|
where(properties.to_h { |k, v| ["properties.#{k}", v] })
|
|
17
|
-
when /mysql|trilogy/
|
|
17
|
+
when /mysql|trilogy/i
|
|
18
18
|
where("JSON_CONTAINS(properties, ?, '$') = 1", properties.to_json)
|
|
19
|
-
when /
|
|
19
|
+
when /postg/i
|
|
20
20
|
case columns_hash["properties"].type
|
|
21
21
|
when :hstore
|
|
22
22
|
properties.inject(all) do |relation, (k, v)|
|
|
@@ -31,7 +31,7 @@ module Ahoy
|
|
|
31
31
|
else
|
|
32
32
|
where("properties::jsonb @> ?", properties.to_json)
|
|
33
33
|
end
|
|
34
|
-
when /sqlite/
|
|
34
|
+
when /sqlite/i
|
|
35
35
|
properties.inject(all) do |relation, (k, v)|
|
|
36
36
|
if v.nil?
|
|
37
37
|
relation.where("JSON_EXTRACT(properties, ?) IS NULL", "$.#{k}")
|
|
@@ -50,16 +50,16 @@ module Ahoy
|
|
|
50
50
|
props.flatten!
|
|
51
51
|
|
|
52
52
|
relation = all
|
|
53
|
-
adapter_name = respond_to?(:
|
|
53
|
+
adapter_name = respond_to?(:connection_db_config) ? connection_db_config.adapter.to_s : "mongoid"
|
|
54
54
|
case adapter_name
|
|
55
55
|
when "mongoid"
|
|
56
56
|
raise "Adapter not supported: #{adapter_name}"
|
|
57
|
-
when /mysql|trilogy/
|
|
57
|
+
when /mysql|trilogy/i
|
|
58
58
|
props.each do |prop|
|
|
59
|
-
quoted_prop =
|
|
59
|
+
quoted_prop = connection_pool.with_connection { |c| c.quote("$.#{prop}") }
|
|
60
60
|
relation = relation.group("JSON_UNQUOTE(JSON_EXTRACT(properties, #{quoted_prop}))")
|
|
61
61
|
end
|
|
62
|
-
when /
|
|
62
|
+
when /postg/i
|
|
63
63
|
# convert to jsonb to fix
|
|
64
64
|
# could not identify an equality operator for type json
|
|
65
65
|
# and for text columns
|
|
@@ -67,12 +67,12 @@ module Ahoy
|
|
|
67
67
|
cast = [:jsonb, :hstore].include?(column_type) ? "" : "::jsonb"
|
|
68
68
|
|
|
69
69
|
props.each do |prop|
|
|
70
|
-
quoted_prop =
|
|
70
|
+
quoted_prop = connection_pool.with_connection { |c| c.quote(prop) }
|
|
71
71
|
relation = relation.group("properties#{cast} -> #{quoted_prop}")
|
|
72
72
|
end
|
|
73
|
-
when /sqlite/
|
|
73
|
+
when /sqlite/i
|
|
74
74
|
props.each do |prop|
|
|
75
|
-
quoted_prop =
|
|
75
|
+
quoted_prop = connection_pool.with_connection { |c| c.quote("$.#{prop}") }
|
|
76
76
|
relation = relation.group("JSON_EXTRACT(properties, #{quoted_prop})")
|
|
77
77
|
end
|
|
78
78
|
else
|
data/lib/ahoy/tracker.rb
CHANGED
|
@@ -43,13 +43,13 @@ module Ahoy
|
|
|
43
43
|
if defer
|
|
44
44
|
set_cookie("ahoy_track", true, nil, false)
|
|
45
45
|
else
|
|
46
|
-
delete_cookie("ahoy_track")
|
|
46
|
+
delete_cookie("ahoy_track", false)
|
|
47
47
|
|
|
48
48
|
data = {
|
|
49
49
|
visit_token: visit_token,
|
|
50
50
|
visitor_token: visitor_token,
|
|
51
51
|
user_id: user.try(:id),
|
|
52
|
-
started_at: trusted_time(started_at)
|
|
52
|
+
started_at: trusted_time(started_at)
|
|
53
53
|
}.merge(visit_properties).select { |_, v| v }
|
|
54
54
|
|
|
55
55
|
@store.track_visit(data)
|
|
@@ -142,7 +142,7 @@ module Ahoy
|
|
|
142
142
|
def reset_visit
|
|
143
143
|
delete_cookie("ahoy_visit")
|
|
144
144
|
delete_cookie("ahoy_events")
|
|
145
|
-
delete_cookie("ahoy_track")
|
|
145
|
+
delete_cookie("ahoy_track", false)
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
def exclude?
|
|
@@ -179,8 +179,15 @@ module Ahoy
|
|
|
179
179
|
request.cookie_jar[name] = cookie
|
|
180
180
|
end
|
|
181
181
|
|
|
182
|
-
def delete_cookie(name)
|
|
183
|
-
|
|
182
|
+
def delete_cookie(name, use_domain = true)
|
|
183
|
+
if request && request.cookie_jar[name]
|
|
184
|
+
options = Ahoy.cookie_options.slice(:path)
|
|
185
|
+
if use_domain
|
|
186
|
+
domain = Ahoy.cookie_options[:domain] || Ahoy.cookie_domain
|
|
187
|
+
options[:domain] = domain if domain
|
|
188
|
+
end
|
|
189
|
+
request.cookie_jar.delete(name, **options)
|
|
190
|
+
end
|
|
184
191
|
end
|
|
185
192
|
|
|
186
193
|
def trusted_time(time = nil)
|
|
@@ -241,7 +248,7 @@ module Ahoy
|
|
|
241
248
|
end
|
|
242
249
|
|
|
243
250
|
def visitor_anonymity_set
|
|
244
|
-
@visitor_anonymity_set ||= Digest::UUID.uuid_v5(UUID_NAMESPACE, ["visitor", Ahoy.mask_ip(request.remote_ip), request.user_agent].join("/"))
|
|
251
|
+
@visitor_anonymity_set ||= request && Digest::UUID.uuid_v5(UUID_NAMESPACE, ["visitor", Ahoy.mask_ip(request.remote_ip), request.user_agent].join("/"))
|
|
245
252
|
end
|
|
246
253
|
|
|
247
254
|
def visit_cookie
|
data/lib/ahoy/version.rb
CHANGED
|
@@ -33,10 +33,6 @@ module Ahoy
|
|
|
33
33
|
properties_type == "text" || (properties_type == "json" && ActiveRecord::Base.connection.try(:mariadb?))
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def serialize_options
|
|
37
|
-
ActiveRecord::VERSION::STRING.to_f >= 7.1 ? "coder: JSON" : "JSON"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
36
|
# use connection_db_config instead of connection.adapter
|
|
41
37
|
# so database connection isn't needed
|
|
42
38
|
def adapter
|
|
@@ -11,12 +11,12 @@ module Ahoy
|
|
|
11
11
|
|
|
12
12
|
selection =
|
|
13
13
|
if activerecord && mongoid
|
|
14
|
-
puts
|
|
14
|
+
puts <<~MSG
|
|
15
15
|
|
|
16
|
-
Which data store would you like to use?
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
Which data store would you like to use?
|
|
17
|
+
1. ActiveRecord (default)
|
|
18
|
+
2. Mongoid
|
|
19
|
+
3. Neither
|
|
20
20
|
MSG
|
|
21
21
|
|
|
22
22
|
ask(">")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Ahoy.js v0.4.
|
|
2
|
+
* Ahoy.js v0.4.5
|
|
3
3
|
* Simple, powerful JavaScript analytics
|
|
4
4
|
* https://github.com/ankane/ahoy.js
|
|
5
5
|
* MIT License
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
function destroyCookie(name) {
|
|
122
|
-
Cookies.set(name, "", -1);
|
|
122
|
+
Cookies.set(name, "", -1, config.cookieDomain || config.domain);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function log(message) {
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ahoy_matey
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Kane
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -16,14 +15,28 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '7.2'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '7.2'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: cgi
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
27
40
|
- !ruby/object:Gem::Dependency
|
|
28
41
|
name: device_detector
|
|
29
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,7 +65,6 @@ dependencies:
|
|
|
52
65
|
- - ">="
|
|
53
66
|
- !ruby/object:Gem::Version
|
|
54
67
|
version: '0.4'
|
|
55
|
-
description:
|
|
56
68
|
email: andrew@ankane.org
|
|
57
69
|
executables: []
|
|
58
70
|
extensions: []
|
|
@@ -97,7 +109,6 @@ homepage: https://github.com/ankane/ahoy
|
|
|
97
109
|
licenses:
|
|
98
110
|
- MIT
|
|
99
111
|
metadata: {}
|
|
100
|
-
post_install_message:
|
|
101
112
|
rdoc_options: []
|
|
102
113
|
require_paths:
|
|
103
114
|
- lib
|
|
@@ -105,15 +116,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
105
116
|
requirements:
|
|
106
117
|
- - ">="
|
|
107
118
|
- !ruby/object:Gem::Version
|
|
108
|
-
version: '3'
|
|
119
|
+
version: '3.3'
|
|
109
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
121
|
requirements:
|
|
111
122
|
- - ">="
|
|
112
123
|
- !ruby/object:Gem::Version
|
|
113
124
|
version: '0'
|
|
114
125
|
requirements: []
|
|
115
|
-
rubygems_version:
|
|
116
|
-
signing_key:
|
|
126
|
+
rubygems_version: 4.0.6
|
|
117
127
|
specification_version: 4
|
|
118
128
|
summary: Simple, powerful, first-party analytics for Rails
|
|
119
129
|
test_files: []
|