Use ActiveRecordTokenStore by default, and transition to safely

Andrew Kane committed Mar 23, 2016
commit 10622c8f51a03939af9a80cd2f4f961529e6b055
Showing 12 changed files with 61 additions and 78 deletions
CHANGELOG.md +7 -1
@@ @@ -1,6 +1,12 @@
- ## 1.3.1
+ ## 1.4.0 [unreleased]
+ - Use `ActiveRecordTokenStore` by default (integer instead of uuid for id)
+ - Detect database for `rails g ahoy:stores:active_record` for easier installation
+ - Use `safely` as default exception handler
- Fixed issue with log silencer
+
+ ## 1.3.1
+
- Raise errors in test environment
## 1.3.0
README.md +20 -53
@@ @@ -25,9 +25,7 @@ And add the javascript file in `app/assets/javascripts/application.js` after jQu
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.
- - [PostgreSQL](#postgresql)
- - [MySQL](#mysql-or-sqlite)
- - [SQLite](#mysql-or-sqlite)
+ - [PostgreSQL, MySQL, or SQLite](#postgresql-mysql-or-sqlite)
- [MongoDB](#mongodb)
- [Fluentd](#fluentd)
- [RabbitMQ](#rabbitmq)
@@ @@ -35,46 +33,15 @@ Ahoy supports a number of data stores out of the box. You can start with one of
- [Logs](#logs)
- [Custom](#custom)
- ### PostgreSQL
+ ### PostgreSQL, MySQL, or SQLite
- For Rails 4.2 and PostgreSQL 9.4 or greater, use:
-
- ```sh
- rails generate ahoy:stores:active_record -d postgresql-jsonb
- rake db:migrate
- ```
-
- For Rails 4 and PostgreSQL 9.2 or greater, use:
-
- ```sh
- rails generate ahoy:stores:active_record -d postgresql
- rake db:migrate
- ```
-
- Otherwise, follow the instructions for MySQL.
-
- ### MySQL or SQLite
-
- Add [activeuuid](https://github.com/jashmenn/activeuuid) to your Gemfile.
-
- ```ruby
- gem 'activeuuid', '>= 0.5.0'
- ```
-
- And run:
+ Run:
```sh
rails generate ahoy:stores:active_record
rake db:migrate
```
- If you just want visits, run:
-
- ```sh
- rails generate ahoy:stores:active_record_visits
- rake db:migrate
- ```
-
### MongoDB
```sh
@@ @@ -217,7 +184,7 @@ ahoy.authenticate(user)
Stores are built to be highly customizable.
```ruby
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
# add methods here
end
```
@@ @@ -227,7 +194,7 @@ end
Exclude visits and events from being tracked with:
```ruby
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
def exclude?
bot? || request.ip == "192.168.1.1"
end
@@ @@ -239,7 +206,7 @@ Bots are excluded by default.
### Track Additional Values
```ruby
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
def track_visit(options)
super do |visit|
visit.gclid = visit_properties.landing_params["gclid"]
@@ @@ -259,7 +226,7 @@ end
If you use a method other than `current_user`, set it here:
```ruby
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
def user
controller.true_user
end
@@ @@ -268,18 +235,12 @@ end
### Report Exceptions
- Exceptions are rescued so analytics do not break your app.
-
- Ahoy uses [Errbase](https://github.com/ankane/errbase) to try to report them to a service by default.
+ 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.
To customize this, use:
```ruby
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
- def report_exception(e)
- Rollbar.report_exception(e)
- end
- end
+ Safely.report_exception_method = proc { |e| Rollbar.error(e) }
```
### Use Different Models
@@ @@ -287,7 +248,7 @@ end
For ActiveRecord and Mongoid stores
```ruby
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
def visit_model
CustomVisit
end
@@ @@ -355,11 +316,13 @@ First, generate a migration and add a `visit_id` column.
```ruby
class AddVisitIdToOrders < ActiveRecord::Migration
def change
- add_column :orders, :visit_id, :uuid
+ add_column :orders, :visit_id, :integer
end
end
```
+ **Note**: Use the `uuid` column type if the `id` column on `visits` is a `uuid`.
+
Then, add `visitable` to the model.
```ruby
@@ @@ -505,7 +468,7 @@ added_item_ids = Ahoy::Event.where(user_id: viewed_store_ids, name: "Added item
viewed_checkout_ids = Ahoy::Event.where(user_id: added_item_ids, name: "Viewed checkout").uniq.pluck(:user_id)
```
- The same approach also works with visitor ids.
+ The same approach also works with visitor tokens.
## Native Apps
@@ @@ -513,7 +476,7 @@ The same approach also works with visitor ids.
When a user launches the app, create a visit.
- Generate a `visit_id` and `visitor_id` as [UUIDs](http://en.wikipedia.org/wiki/Universally_unique_identifier).
+ Generate a `visit_token` and `visitor_token` as [UUIDs](http://en.wikipedia.org/wiki/Universally_unique_identifier).
Send these values in the `Ahoy-Visit` and `Ahoy-Visitor` headers with all requests.
@@ @@ -540,7 +503,11 @@ Use an array to pass multiple events at once.
## Upgrading
- ### PostgreSQL 9.4 + JSONB
+ ### 1.4.0
+
+ There’s nothing to do, but it’s worth noting the default store was changed from `ActiveRecordStore` to `ActiveRecordTokenStore` for new installations.
+
+ ### json -> jsonb
Create a migration to add a new `jsonb` column.
ahoy_matey.gemspec +1 -1
@@ @@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "user_agent_parser"
spec.add_dependency "request_store"
spec.add_dependency "uuidtools"
- spec.add_dependency "errbase"
+ spec.add_dependency "safely_block"
spec.add_dependency "rack-attack"
spec.add_development_dependency "bundler", "~> 1.5"
ahoy.rb b/lib/ahoy.rb +1 -1
@@ @@ -6,7 +6,7 @@ require "referer-parser"
require "user_agent_parser"
require "request_store"
require "uuidtools"
- require "errbase"
+ require "safely_block"
require "ahoy/version"
require "ahoy/tracker"
ahoy/stores/active_record_token_store.rb b/lib/ahoy/stores/active_record_token_store.rb +2 -1
@@ @@ -7,7 +7,8 @@ module Ahoy
v.visit_token = ahoy.visit_token
v.visitor_token = ahoy.visitor_token
v.user = user if v.respond_to?(:user=)
- v.created_at = options[:started_at]
+ v.started_at = options[:started_at] if v.respond_to?(:started_at)
+ v.created_at = options[:started_at] if v.respond_to?(:created_at)
end
set_visit_properties(visit)
ahoy/stores/base_store.rb b/lib/ahoy/stores/base_store.rb +1 -1
@@ @@ -27,7 +27,7 @@ module Ahoy
end
def report_exception(e)
- Errbase.report(e)
+ raise e
end
def user
ahoy/tracker.rb b/lib/ahoy/tracker.rb +6 -7
@@ @@ -124,15 +124,14 @@ module Ahoy
@store.exclude?
end
+ # odd pattern for backwards compatibility
+ # TODO remove this method in next major release
def report_exception(e)
- begin
+ safely do
@store.report_exception(e)
- rescue
- # fail-safe
- $stderr.puts "Error reporting exception"
- end
- if Rails.env.development? || Rails.env.test?
- raise e
+ if Rails.env.development? || Rails.env.test?
+ raise e
+ end
end
end
generators/ahoy/stores/active_record_events_generator.rb b/lib/generators/ahoy/stores/active_record_events_generator.rb +11 -1
@@ @@ -24,7 +24,8 @@ module Ahoy
end
def copy_migration
- unless options["database"].in?([nil, "postgresql", "postgresql-jsonb"])
+ @database = options["database"] || detect_database
+ unless @database.in?([nil, "postgresql", "postgresql-jsonb", "mysql", "sqlite"])
raise Thor::Error, "Unknown database option"
end
migration_template "active_record_events_migration.rb", "db/migrate/create_ahoy_events.rb"
@@ @@ -37,6 +38,15 @@ module Ahoy
def create_initializer
template "active_record_initializer.rb", "config/initializers/ahoy.rb"
end
+
+ def detect_database
+ postgresql_version = ActiveRecord::Base.connection.send(:postgresql_version) rescue 0
+ if postgresql_version >= 90400
+ "postgresql-jsonb"
+ elsif postgresql_version >= 90200
+ "postgresql"
+ end
+ end
end
end
end
generators/ahoy/stores/templates/active_record_event_model.rb b/lib/generators/ahoy/stores/templates/active_record_event_model.rb +1 -1
@@ @@ -3,7 +3,7 @@ module Ahoy
self.table_name = "ahoy_events"
belongs_to :visit
- belongs_to :user<% if options["database"].blank? %>
+ belongs_to :user<% unless %w(postgresql postgresql-jsonb).include?(@database) %>
serialize :properties, JSON<% end %>
end
generators/ahoy/stores/templates/active_record_events_migration.rb b/lib/generators/ahoy/stores/templates/active_record_events_migration.rb +6 -7
@@ @@ -1,20 +1,19 @@
class <%= migration_class_name %> < ActiveRecord::Migration
def change
- create_table :ahoy_events, id: false do |t|
- t.uuid :id, default: nil, primary_key: true
- t.uuid :visit_id, default: nil
+ create_table :ahoy_events do |t|
+ t.integer :visit_id
# user
t.integer :user_id
# add t.string :user_type if polymorphic
t.string :name
- t.<% case options["database"] when "postgresql" %>json<% when "postgresql-jsonb" %>jsonb<% else %>text<% end %> :properties
+ t.<% case @database when "postgresql" %>json<% when "postgresql-jsonb" %>jsonb<% else %>text<% end %> :properties
t.timestamp :time
end
- add_index :ahoy_events, [:visit_id]
- add_index :ahoy_events, [:user_id]
- add_index :ahoy_events, [:time]
+ add_index :ahoy_events, [:visit_id, :name]
+ add_index :ahoy_events, [:user_id, :name]
+ add_index :ahoy_events, [:name, :time]
end
end
generators/ahoy/stores/templates/active_record_initializer.rb b/lib/generators/ahoy/stores/templates/active_record_initializer.rb +1 -1
@@ @@ -1,3 +1,3 @@
- class Ahoy::Store < Ahoy::Stores::ActiveRecordStore
+ class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
# customize here
end
generators/ahoy/stores/templates/active_record_visits_migration.rb b/lib/generators/ahoy/stores/templates/active_record_visits_migration.rb +4 -3
@@ @@ -1,8 +1,8 @@
class <%= migration_class_name %> < ActiveRecord::Migration
def change
- create_table :visits, id: false do |t|
- t.uuid :id, default: nil, primary_key: true
- t.uuid :visitor_id, default: nil
+ create_table :visits do |t|
+ t.string :visit_token
+ t.string :visitor_token
# the rest are recommended but optional
# simply remove the columns you don't want
@@ @@ -51,6 +51,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration
t.timestamp :started_at
end
+ add_index :visits, [:visit_token], unique: true
add_index :visits, [:user_id]
end
end