ahoy_matey 1.3.1 → 1.4.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: ac410ebebcbaf5aad9ccc62e1880017a529122f6
4
- data.tar.gz: 9394bb160b09cc8b28d15c23c0d81443b37547c9
3
+ metadata.gz: 181105196800b983c765eacf7faa0ad9280a1553
4
+ data.tar.gz: 67a7a2cb8dea093d979323b384b18d3b7f4e4ba7
5
5
  SHA512:
6
- metadata.gz: df2fd19329ea584adfc8a6a2f730fe651650f812c9806e75ade1869376fd787ffa7537621cf518ac8ffd42e9e83ee6e21828c826023c957622c8f94b8c544cf4
7
- data.tar.gz: 7ae8ddc2287e8182055cb293558286127c49c594b0fcd3cb5516571d4ff3c1ecd71c1cc4de469f7d4dfccaa5f493b5cdc4037c734bb96a140173f5457d6c397f
6
+ metadata.gz: a3dd6aeb1bd934d5ae71b84b38188c8c991a28c764aeecebf1566e3f675c120953c3a443ad38330e5db68d530e7fd1bce7ad2d5f3e469fe8e6b403f4381a6257
7
+ data.tar.gz: ea652c7992e43801a5f6dc5bfac7284c336a6ab11e544a1298b96bf100807251f4059355f6650932f42a85ade1a6a2eac9e3204f14a32186289feabf26d03165
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
- ## 1.3.1
1
+ ## 1.4.0
2
2
 
3
+ - Use `ActiveRecordTokenStore` by default (integer instead of uuid for id)
4
+ - Detect database for `rails g ahoy:stores:active_record` for easier installation
5
+ - Use `safely` as default exception handler
3
6
  - Fixed issue with log silencer
7
+
8
+ ## 1.3.1
9
+
4
10
  - Raise errors in test environment
5
11
 
6
12
  ## 1.3.0
data/README.md CHANGED
@@ -1,17 +1,11 @@
1
1
  # Ahoy
2
2
 
3
- :fire: Never build an analytics platform from scratch again.
4
-
5
- Ahoy provides a solid foundation to track visits and events in Ruby, JavaScript, and native apps.
6
-
7
- Works with any data store so you can easily scale.
3
+ Ahoy provides a solid foundation to track visits and events in Ruby, JavaScript, and native apps. Works with any data store so you can easily scale.
8
4
 
9
5
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
10
6
 
11
7
  :postbox: To track emails, check out [Ahoy Email](https://github.com/ankane/ahoy_email).
12
8
 
13
- See [upgrade instructions](#100) on how to move to 1.0.
14
-
15
9
  ## Installation
16
10
 
17
11
  Add this line to your application’s Gemfile:
@@ -31,56 +25,23 @@ And add the javascript file in `app/assets/javascripts/application.js` after jQu
31
25
 
32
26
  Ahoy supports a number of data stores out of the box. You can start with one of them and customize as needed, or create your own store from scratch.
33
27
 
34
- - [PostgreSQL](#postgresql)
35
- - [MySQL](#mysql-or-sqlite)
36
- - [SQLite](#mysql-or-sqlite)
28
+ - [PostgreSQL, MySQL, or SQLite](#postgresql-mysql-or-sqlite)
37
29
  - [MongoDB](#mongodb)
38
30
  - [Fluentd](#fluentd)
39
- - [RabbitMQ](#rabbitmq-master)
40
- - [Kinesis Firehose](#kinesis-firehose-master)
31
+ - [RabbitMQ](#rabbitmq)
32
+ - [Amazon Kinesis Firehose](#amazon-kinesis-firehose)
41
33
  - [Logs](#logs)
42
34
  - [Custom](#custom)
43
35
 
44
- ### PostgreSQL
45
-
46
- For Rails 4.2 and PostgreSQL 9.4 or greater, use:
47
-
48
- ```sh
49
- rails generate ahoy:stores:active_record -d postgresql-jsonb
50
- rake db:migrate
51
- ```
52
-
53
- For Rails 4 and PostgreSQL 9.2 or greater, use:
54
-
55
- ```sh
56
- rails generate ahoy:stores:active_record -d postgresql
57
- rake db:migrate
58
- ```
59
-
60
- Otherwise, follow the instructions for MySQL.
61
-
62
- ### MySQL or SQLite
63
-
64
- Add [activeuuid](https://github.com/jashmenn/activeuuid) to your Gemfile.
65
-
66
- ```ruby
67
- gem 'activeuuid', '>= 0.5.0'
68
- ```
36
+ ### PostgreSQL, MySQL, or SQLite
69
37
 
70
- And run:
38
+ Run:
71
39
 
72
40
  ```sh
73
41
  rails generate ahoy:stores:active_record
74
42
  rake db:migrate
75
43
  ```
76
44
 
77
- If you just want visits, run:
78
-
79
- ```sh
80
- rails generate ahoy:stores:active_record_visits
81
- rake db:migrate
82
- ```
83
-
84
45
  ### MongoDB
85
46
 
86
47
  ```sh
@@ -119,7 +80,7 @@ rails generate ahoy:stores:bunny
119
80
 
120
81
  Use `ENV["RABBITMQ_URL"]` to configure.
121
82
 
122
- ### Kinesis Firehose
83
+ ### Amazon Kinesis Firehose
123
84
 
124
85
  Add [aws-sdk](https://github.com/aws/aws-sdk-ruby) to your Gemfile.
125
86
 
@@ -223,7 +184,7 @@ ahoy.authenticate(user)
223
184
  Stores are built to be highly customizable.
224
185
 
225
186
  ```ruby
226
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
187
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
227
188
  # add methods here
228
189
  end
229
190
  ```
@@ -233,7 +194,7 @@ end
233
194
  Exclude visits and events from being tracked with:
234
195
 
235
196
  ```ruby
236
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
197
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
237
198
  def exclude?
238
199
  bot? || request.ip == "192.168.1.1"
239
200
  end
@@ -245,7 +206,7 @@ Bots are excluded by default.
245
206
  ### Track Additional Values
246
207
 
247
208
  ```ruby
248
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
209
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
249
210
  def track_visit(options)
250
211
  super do |visit|
251
212
  visit.gclid = visit_properties.landing_params["gclid"]
@@ -265,7 +226,7 @@ end
265
226
  If you use a method other than `current_user`, set it here:
266
227
 
267
228
  ```ruby
268
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
229
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
269
230
  def user
270
231
  controller.true_user
271
232
  end
@@ -274,18 +235,12 @@ end
274
235
 
275
236
  ### Report Exceptions
276
237
 
277
- Exceptions are rescued so analytics do not break your app.
278
-
279
- Ahoy uses [Errbase](https://github.com/ankane/errbase) to try to report them to a service by default.
238
+ Exceptions are rescued so analytics do not break your app. Ahoy uses [Safely](https://github.com/ankane/safely) to try to report them to a service by default.
280
239
 
281
240
  To customize this, use:
282
241
 
283
242
  ```ruby
284
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
285
- def report_exception(e)
286
- Rollbar.report_exception(e)
287
- end
288
- end
243
+ Safely.report_exception_method = proc { |e| Rollbar.error(e) }
289
244
  ```
290
245
 
291
246
  ### Use Different Models
@@ -293,7 +248,7 @@ end
293
248
  For ActiveRecord and Mongoid stores
294
249
 
295
250
  ```ruby
296
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
251
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
297
252
  def visit_model
298
253
  CustomVisit
299
254
  end
@@ -361,11 +316,13 @@ First, generate a migration and add a `visit_id` column.
361
316
  ```ruby
362
317
  class AddVisitIdToOrders < ActiveRecord::Migration
363
318
  def change
364
- add_column :orders, :visit_id, :uuid
319
+ add_column :orders, :visit_id, :integer
365
320
  end
366
321
  end
367
322
  ```
368
323
 
324
+ **Note**: Use the `uuid` column type if the `id` column on `visits` is a `uuid`.
325
+
369
326
  Then, add `visitable` to the model.
370
327
 
371
328
  ```ruby
@@ -406,7 +363,13 @@ Ahoy.geocode = :async
406
363
 
407
364
  For Rails 4.0 and 4.1, you’ll need to add [activejob_backport](https://github.com/ankane/activejob_backport).
408
365
 
409
- Or disable it with:
366
+ To change the queue name (`ahoy` by default), use:
367
+
368
+ ```ruby
369
+ Ahoy.job_queue = :low_priority
370
+ ```
371
+
372
+ Or disable geocoding with:
410
373
 
411
374
  ```ruby
412
375
  Ahoy.geocode = false
@@ -505,7 +468,7 @@ added_item_ids = Ahoy::Event.where(user_id: viewed_store_ids, name: "Added item
505
468
  viewed_checkout_ids = Ahoy::Event.where(user_id: added_item_ids, name: "Viewed checkout").uniq.pluck(:user_id)
506
469
  ```
507
470
 
508
- The same approach also works with visitor ids.
471
+ The same approach also works with visitor tokens.
509
472
 
510
473
  ## Native Apps
511
474
 
@@ -513,7 +476,7 @@ The same approach also works with visitor ids.
513
476
 
514
477
  When a user launches the app, create a visit.
515
478
 
516
- Generate a `visit_id` and `visitor_id` as [UUIDs](http://en.wikipedia.org/wiki/Universally_unique_identifier).
479
+ Generate a `visit_token` and `visitor_token` as [UUIDs](http://en.wikipedia.org/wiki/Universally_unique_identifier).
517
480
 
518
481
  Send these values in the `Ahoy-Visit` and `Ahoy-Visitor` headers with all requests.
519
482
 
@@ -540,25 +503,34 @@ Use an array to pass multiple events at once.
540
503
 
541
504
  ## Upgrading
542
505
 
543
- ### PostgreSQL 9.4 + JSONB
506
+ ### 1.4.0
544
507
 
545
- ```sh
546
- rails g migration change_properties_to_jsonb_on_ahoy_events
508
+ There’s nothing to do, but it’s worth noting the default store was changed from `ActiveRecordStore` to `ActiveRecordTokenStore` for new installations.
509
+
510
+ ### json -> jsonb
511
+
512
+ Create a migration to add a new `jsonb` column.
513
+
514
+ ```ruby
515
+ rename_column :ahoy_events, :properties, :properties_json
516
+ add_column :ahoy_events, :properties, :jsonb
547
517
  ```
548
518
 
549
- And add:
519
+ Restart your web server immediately afterwards, as Ahoy will rescue and report errors until then.
550
520
 
551
- ```rb
552
- def up
553
- change_column :ahoy_events, :properties, :jsonb, using: "properties::jsonb"
554
- end
521
+ Sync the new column.
555
522
 
556
- def down
557
- change_column :ahoy_events, :properties, :json
523
+ ```ruby
524
+ Ahoy::Event.where(properties: nil).select(:id).find_in_batches do |events|
525
+ Ahoy::Event.where(id: events.map(&:id)).update_all("properties = properties_json::jsonb")
558
526
  end
559
527
  ```
560
528
 
561
- Note: This will lock the table while the migration is running.
529
+ Then create a migration to drop the old column.
530
+
531
+ ```ruby
532
+ remove_column :ahoy_events, :properties_json
533
+ ```
562
534
 
563
535
  ### 1.0.0
564
536
 
data/ahoy_matey.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "rails"
21
+ spec.add_dependency "railties"
22
22
  spec.add_dependency "addressable"
23
23
  spec.add_dependency "browser", "~> 2.0"
24
24
  spec.add_dependency "geocoder"
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency "user_agent_parser"
27
27
  spec.add_dependency "request_store"
28
28
  spec.add_dependency "uuidtools"
29
- spec.add_dependency "errbase"
29
+ spec.add_dependency "safely_block"
30
30
  spec.add_dependency "rack-attack"
31
31
 
32
32
  spec.add_development_dependency "bundler", "~> 1.5"
data/lib/ahoy.rb CHANGED
@@ -1,4 +1,3 @@
1
- require "rails"
2
1
  require "active_support/core_ext"
3
2
  require "addressable/uri"
4
3
  require "browser"
@@ -7,7 +6,7 @@ require "referer-parser"
7
6
  require "user_agent_parser"
8
7
  require "request_store"
9
8
  require "uuidtools"
10
- require "errbase"
9
+ require "safely_block"
11
10
 
12
11
  require "ahoy/version"
13
12
  require "ahoy/tracker"
@@ -27,7 +26,6 @@ require "ahoy/stores/fluentd_store"
27
26
  require "ahoy/stores/mongoid_store"
28
27
  require "ahoy/stores/kinesis_firehose_store"
29
28
  require "ahoy/stores/bunny_store"
30
- require "ahoy/log_silencer"
31
29
  require "ahoy/engine"
32
30
  require "ahoy/warden" if defined?(Warden)
33
31
 
@@ -77,6 +75,9 @@ module Ahoy
77
75
  mattr_accessor :throttle_period
78
76
  self.throttle_period = 1.minute
79
77
 
78
+ mattr_accessor :job_queue
79
+ self.job_queue = :ahoy
80
+
80
81
  def self.ensure_uuid(id)
81
82
  valid = UUIDTools::UUID.parse(id) rescue nil
82
83
  if valid
data/lib/ahoy/engine.rb CHANGED
@@ -1,12 +1,30 @@
1
1
  module Ahoy
2
2
  class Engine < ::Rails::Engine
3
3
  initializer "ahoy.middleware", after: "sprockets.environment" do |app|
4
- Rails::Rack::Logger.send(:prepend, Ahoy::LogSilencer) if Ahoy.quiet
5
-
6
4
  if Ahoy.throttle
7
5
  require "ahoy/throttle"
8
6
  app.middleware.use Ahoy::Throttle
9
7
  end
8
+
9
+ next unless Ahoy.quiet
10
+
11
+ # Parse PATH_INFO by assets prefix
12
+ AHOY_PREFIX = "/ahoy/".freeze
13
+
14
+ # Just create an alias for call in middleware
15
+ Rails::Rack::Logger.class_eval do
16
+ def call_with_quiet_ahoy(env)
17
+ if env["PATH_INFO"].start_with?(AHOY_PREFIX) && logger.respond_to?(:silence_logger)
18
+ logger.silence_logger do
19
+ call_without_quiet_ahoy(env)
20
+ end
21
+ else
22
+ call_without_quiet_ahoy(env)
23
+ end
24
+ end
25
+ alias_method :call_without_quiet_ahoy, :call
26
+ alias_method :call, :call_with_quiet_ahoy
27
+ end
10
28
  end
11
29
  end
12
30
  end
@@ -7,7 +7,8 @@ module Ahoy
7
7
  v.visit_token = ahoy.visit_token
8
8
  v.visitor_token = ahoy.visitor_token
9
9
  v.user = user if v.respond_to?(:user=)
10
- v.created_at = options[:started_at]
10
+ v.started_at = options[:started_at] if v.respond_to?(:started_at)
11
+ v.created_at = options[:started_at] if v.respond_to?(:created_at)
11
12
  end
12
13
 
13
14
  set_visit_properties(visit)
@@ -27,7 +27,7 @@ module Ahoy
27
27
  end
28
28
 
29
29
  def report_exception(e)
30
- Errbase.report(e)
30
+ raise e
31
31
  end
32
32
 
33
33
  def user
@@ -73,7 +73,7 @@ module Ahoy
73
73
 
74
74
  def geocode(visit)
75
75
  if Ahoy.geocode == :async
76
- Ahoy::GeocodeJob.perform_later(visit)
76
+ Ahoy::GeocodeJob.set(queue: Ahoy.job_queue).perform_later(visit)
77
77
  end
78
78
  end
79
79
 
data/lib/ahoy/tracker.rb CHANGED
@@ -124,15 +124,14 @@ module Ahoy
124
124
  @store.exclude?
125
125
  end
126
126
 
127
+ # odd pattern for backwards compatibility
128
+ # TODO remove this method in next major release
127
129
  def report_exception(e)
128
- begin
130
+ safely do
129
131
  @store.report_exception(e)
130
- rescue
131
- # fail-safe
132
- $stderr.puts "Error reporting exception"
133
- end
134
- if Rails.env.development? || Rails.env.test?
135
- raise e
132
+ if Rails.env.development? || Rails.env.test?
133
+ raise e
134
+ end
136
135
  end
137
136
  end
138
137
 
data/lib/ahoy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "1.3.1"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -24,7 +24,8 @@ module Ahoy
24
24
  end
25
25
 
26
26
  def copy_migration
27
- unless options["database"].in?([nil, "postgresql", "postgresql-jsonb"])
27
+ @database = options["database"] || detect_database
28
+ unless @database.in?([nil, "postgresql", "postgresql-jsonb", "mysql", "sqlite"])
28
29
  raise Thor::Error, "Unknown database option"
29
30
  end
30
31
  migration_template "active_record_events_migration.rb", "db/migrate/create_ahoy_events.rb"
@@ -37,6 +38,15 @@ module Ahoy
37
38
  def create_initializer
38
39
  template "active_record_initializer.rb", "config/initializers/ahoy.rb"
39
40
  end
41
+
42
+ def detect_database
43
+ postgresql_version = ActiveRecord::Base.connection.send(:postgresql_version) rescue 0
44
+ if postgresql_version >= 90400
45
+ "postgresql-jsonb"
46
+ elsif postgresql_version >= 90200
47
+ "postgresql"
48
+ end
49
+ end
40
50
  end
41
51
  end
42
52
  end
@@ -3,7 +3,7 @@ module Ahoy
3
3
  self.table_name = "ahoy_events"
4
4
 
5
5
  belongs_to :visit
6
- belongs_to :user<% if options["database"].blank? %>
6
+ belongs_to :user<% unless %w(postgresql postgresql-jsonb).include?(@database) %>
7
7
 
8
8
  serialize :properties, JSON<% end %>
9
9
  end
@@ -1,20 +1,19 @@
1
1
  class <%= migration_class_name %> < ActiveRecord::Migration
2
2
  def change
3
- create_table :ahoy_events, id: false do |t|
4
- t.uuid :id, default: nil, primary_key: true
5
- t.uuid :visit_id, default: nil
3
+ create_table :ahoy_events do |t|
4
+ t.integer :visit_id
6
5
 
7
6
  # user
8
7
  t.integer :user_id
9
8
  # add t.string :user_type if polymorphic
10
9
 
11
10
  t.string :name
12
- t.<% case options["database"] when "postgresql" %>json<% when "postgresql-jsonb" %>jsonb<% else %>text<% end %> :properties
11
+ t.<% case @database when "postgresql" %>json<% when "postgresql-jsonb" %>jsonb<% else %>text<% end %> :properties
13
12
  t.timestamp :time
14
13
  end
15
14
 
16
- add_index :ahoy_events, [:visit_id]
17
- add_index :ahoy_events, [:user_id]
18
- add_index :ahoy_events, [:time]
15
+ add_index :ahoy_events, [:visit_id, :name]
16
+ add_index :ahoy_events, [:user_id, :name]
17
+ add_index :ahoy_events, [:name, :time]
19
18
  end
20
19
  end
@@ -1,3 +1,3 @@
1
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
1
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
2
2
  # customize here
3
3
  end
@@ -1,8 +1,8 @@
1
1
  class <%= migration_class_name %> < ActiveRecord::Migration
2
2
  def change
3
- create_table :visits, id: false do |t|
4
- t.uuid :id, default: nil, primary_key: true
5
- t.uuid :visitor_id, default: nil
3
+ create_table :visits do |t|
4
+ t.string :visit_token
5
+ t.string :visitor_token
6
6
 
7
7
  # the rest are recommended but optional
8
8
  # simply remove the columns you don't want
@@ -51,6 +51,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration
51
51
  t.timestamp :started_at
52
52
  end
53
53
 
54
+ add_index :visits, [:visit_token], unique: true
54
55
  add_index :visits, [:user_id]
55
56
  end
56
57
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ahoy_matey
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
@@ -11,7 +11,7 @@ cert_chain: []
11
11
  date: 2016-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: railties
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -123,7 +123,7 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: errbase
126
+ name: safely_block
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
@@ -219,7 +219,6 @@ files:
219
219
  - lib/ahoy/deckhands/utm_parameter_deckhand.rb
220
220
  - lib/ahoy/engine.rb
221
221
  - lib/ahoy/geocode_job.rb
222
- - lib/ahoy/log_silencer.rb
223
222
  - lib/ahoy/logger_silencer.rb
224
223
  - lib/ahoy/model.rb
225
224
  - lib/ahoy/stores/active_record_store.rb
@@ -1,16 +0,0 @@
1
- module Ahoy
2
- module LogSilencer
3
- PATH_INFO = "PATH_INFO".freeze
4
- AHOY_PREFIX = "/ahoy/".freeze
5
-
6
- def call(env)
7
- if env[PATH_INFO].start_with?(AHOY_PREFIX) && logger.respond_to?(:silence_logger)
8
- logger.silence_logger do
9
- super
10
- end
11
- else
12
- super
13
- end
14
- end
15
- end
16
- end