vanity 2.2.8 → 2.2.9
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 +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +104 -18
- data/gemfiles/rails32.gemfile.lock +1 -1
- data/gemfiles/rails41.gemfile.lock +1 -1
- data/gemfiles/rails42.gemfile.lock +1 -1
- data/gemfiles/rails42_protected_attributes.gemfile.lock +1 -1
- data/gemfiles/rails5.gemfile.lock +1 -1
- data/lib/generators/templates/add_unique_indexes_migration.rb +28 -0
- data/lib/generators/templates/vanity_migration.rb +4 -2
- data/lib/generators/vanity/add_unique_indexes_generator.rb +15 -0
- data/lib/vanity/adapters/active_record_adapter.rb +14 -4
- data/lib/vanity/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca984620557d326a44e57c76e179701e43c784aa
|
4
|
+
data.tar.gz: 3a27cad8226fbdf3e56709291b1ed2afc1793acd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e3a77b2540e8726b77bc6f5ec80226f39b7f499abd271d2e5bc20c51131998472e0dffa0879cdf799e1a4de7e7b6cc052e1ea2e87b85fc09bb584df21e8293c
|
7
|
+
data.tar.gz: 761fb69735eb0b02e8267a24243bb7cf923ccd8880a14ed691ae55f207aa73c4bed6e5c2566e6179aa264c6defacf519462db3c8106830e5a1432f53607d590c
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
== Unreleased
|
2
2
|
|
3
|
+
== 2.2.9 (2018-02-03)
|
4
|
+
|
5
|
+
* Fix race condition using the activerecord adapater when vanity creates experiments or rows in the conversions table (@fcheung)
|
6
|
+
|
3
7
|
== 2.2.8 (2017-09-26)
|
4
8
|
* Rails 5.1 compatibility (#326, #327, #330, @sebjacobs, @bensheldon, @terracatta)
|
5
9
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -9,13 +9,34 @@ Vanity is an A/B testing framework for Rails that is datastore agnostic.
|
|
9
9
|
|
10
10
|
[](http://github.com/assaf/vanity)
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
<!-- toc -->
|
13
|
+
|
14
|
+
- [Installation](#installation)
|
15
|
+
- [Setup](#setup)
|
16
|
+
* [Datastore](#datastore)
|
17
|
+
+ [Redis Setup](#redis-setup)
|
18
|
+
+ [MongoDB Setup](#mongodb-setup)
|
19
|
+
+ [SQL Database Setup](#sql-database-setup)
|
20
|
+
+ [Forking servers and reconnecting](#forking-servers-and-reconnecting)
|
21
|
+
* [Initialization](#initialization)
|
22
|
+
* [User identification](#user-identification)
|
23
|
+
+ [Rails](#rails)
|
24
|
+
+ [Other](#other)
|
25
|
+
* [Define a A/B test](#define-a-ab-test)
|
26
|
+
* [Present the different options to your users](#present-the-different-options-to-your-users)
|
27
|
+
* [Measure conversion](#measure-conversion)
|
28
|
+
* [Check the report](#check-the-report)
|
29
|
+
+ [Rails report dashboard](#rails-report-dashboard)
|
30
|
+
- [Registering participants with Javascript](#registering-participants-with-javascript)
|
31
|
+
- [Compatibility](#compatibility)
|
32
|
+
- [Testing](#testing)
|
33
|
+
- [Updating documentation](#updating-documentation)
|
34
|
+
- [Contributing](#contributing)
|
35
|
+
- [Credits/License](#creditslicense)
|
36
|
+
|
37
|
+
<!-- tocstop -->
|
38
|
+
|
39
|
+
## Installation
|
19
40
|
|
20
41
|
Add to your Gemfile:
|
21
42
|
|
@@ -26,14 +47,16 @@ gem "vanity"
|
|
26
47
|
(For support for older versions of Rails and Ruby 1.8, please see the [1.9.x
|
27
48
|
branch](https://github.com/assaf/vanity/tree/1-9-stable).)
|
28
49
|
|
29
|
-
|
50
|
+
## Setup
|
51
|
+
|
52
|
+
### Datastore
|
30
53
|
|
31
54
|
Choose a datastore that best fits your needs and preferences for storing
|
32
55
|
experiment results. Choose one of: Redis, MongoDB or an SQL database. While
|
33
56
|
Redis is usually faster, it may add additional complexity to your stack.
|
34
57
|
Datastores should be configured using a `config/vanity.yml`.
|
35
58
|
|
36
|
-
|
59
|
+
#### Redis Setup
|
37
60
|
|
38
61
|
Add to your Gemfile:
|
39
62
|
|
@@ -73,7 +96,7 @@ Vanity.connect!(
|
|
73
96
|
)
|
74
97
|
```
|
75
98
|
|
76
|
-
|
99
|
+
#### MongoDB Setup
|
77
100
|
|
78
101
|
Add to your Gemfile:
|
79
102
|
|
@@ -94,7 +117,7 @@ production:
|
|
94
117
|
database: analytics
|
95
118
|
```
|
96
119
|
|
97
|
-
|
120
|
+
#### SQL Database Setup
|
98
121
|
|
99
122
|
Vanity supports multiple SQL stores (like MySQL, MariaDB, Postgres, Sqlite,
|
100
123
|
etc.) using ActiveRecord, which is built into Rails. If you're using
|
@@ -133,7 +156,7 @@ $ rails generate vanity
|
|
133
156
|
$ rake db:migrate
|
134
157
|
```
|
135
158
|
|
136
|
-
|
159
|
+
#### Forking servers and reconnecting
|
137
160
|
|
138
161
|
If you're using a forking server (like Passenger or Unicorn), you should
|
139
162
|
reconnect after a new worker is created:
|
@@ -165,7 +188,25 @@ Vanity.connect!(
|
|
165
188
|
)
|
166
189
|
```
|
167
190
|
|
168
|
-
|
191
|
+
### Initialization
|
192
|
+
|
193
|
+
If you're using Rails, this is done automagically. Otherwise, some manual setup is required, for example on an app's booting:
|
194
|
+
|
195
|
+
```
|
196
|
+
$redis = Redis.new # or from elsewhere
|
197
|
+
Vanity.configure do |config|
|
198
|
+
# ... any config
|
199
|
+
end
|
200
|
+
Vanity.connect!(
|
201
|
+
adapter: :redis,
|
202
|
+
redis: $redis
|
203
|
+
)
|
204
|
+
Vanity.load!
|
205
|
+
```
|
206
|
+
|
207
|
+
### User identification
|
208
|
+
|
209
|
+
#### Rails
|
169
210
|
|
170
211
|
Turn Vanity on, and pass a reference to a method that identifies a user. For
|
171
212
|
example:
|
@@ -179,7 +220,28 @@ end
|
|
179
220
|
For more information, please see the [identity
|
180
221
|
documentation](http://vanity.labnotes.org/identity.html).
|
181
222
|
|
182
|
-
|
223
|
+
#### Other
|
224
|
+
|
225
|
+
Vanity pulls the identity from a "context" object that responds to `vanity_identity`, so we need to define a `Vanity.context` (this is how the [ActionMailer integration](https://github.com/assaf/vanity/blob/master/lib/vanity/frameworks/rails.rb#L107-L133) works):
|
226
|
+
|
227
|
+
```
|
228
|
+
class AVanityContext
|
229
|
+
def vanity_identity
|
230
|
+
"123"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
Vanity.context = AVanityContext.new() # Any object that responds to `#vanity_identity`
|
235
|
+
```
|
236
|
+
|
237
|
+
If you're using plain ruby objects, you could also alias something in your identity model to respond similarly and then set that as the vanity context:
|
238
|
+
```
|
239
|
+
class User
|
240
|
+
alias_method :vanity_identity, :id
|
241
|
+
end
|
242
|
+
```
|
243
|
+
|
244
|
+
### Define a A/B test
|
183
245
|
|
184
246
|
This experiment goes in the file `experiments/price_options.rb`:
|
185
247
|
|
@@ -200,15 +262,25 @@ metric "Signup (Activation)" do
|
|
200
262
|
end
|
201
263
|
```
|
202
264
|
|
203
|
-
###
|
265
|
+
### Present the different options to your users
|
266
|
+
|
267
|
+
In Rails' templates, this is straightforward:
|
204
268
|
|
205
269
|
```erb
|
206
270
|
<h2>Get started for only $<%= ab_test :price_options %> a month!</h2>
|
207
271
|
```
|
208
272
|
|
209
|
-
|
273
|
+
Outside of templates:
|
210
274
|
|
211
|
-
|
275
|
+
```
|
276
|
+
Vanity.ab_test(:invite_subject)
|
277
|
+
```
|
278
|
+
|
279
|
+
### Measure conversion
|
280
|
+
|
281
|
+
Conversions are created via the `Vanity.track!` method. A user should already be added to an experiment, via `ab_test` before this is called - otherwise, the conversion will be tracked, but the user will not be added to the experiment.
|
282
|
+
|
283
|
+
For example, in Rails:
|
212
284
|
|
213
285
|
```ruby
|
214
286
|
class SignupController < ApplicationController
|
@@ -224,12 +296,26 @@ class SignupController < ApplicationController
|
|
224
296
|
end
|
225
297
|
```
|
226
298
|
|
227
|
-
|
299
|
+
Outside of an Rails controller, for example in a Rack handler:
|
300
|
+
|
301
|
+
```
|
302
|
+
identity_object = Identity.new(env['rack.session'])
|
303
|
+
Vanity.track!(:click, {
|
304
|
+
# can be any object that responds to `to_s` with a string
|
305
|
+
# that contains the unique identifier or the string identifier itself
|
306
|
+
:identity=>identity_object,
|
307
|
+
:values=>[1] # optional
|
308
|
+
})
|
309
|
+
```
|
310
|
+
|
311
|
+
### Check the report
|
228
312
|
|
229
313
|
```sh
|
230
314
|
vanity report --output vanity.html
|
231
315
|
```
|
232
316
|
|
317
|
+
#### Rails report dashboard
|
318
|
+
|
233
319
|
To view metrics and experiment results with the dashboard in Rails 3 & Rails
|
234
320
|
4:
|
235
321
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "vanity/adapters/active_record_adapter"
|
2
|
+
|
3
|
+
class AddVanityUniqueIndexes < ActiveRecord::Migration
|
4
|
+
# Helper methods to ensure we're connecting to the right database, see
|
5
|
+
# https://github.com/assaf/vanity/issues/295.
|
6
|
+
|
7
|
+
def connection
|
8
|
+
@connection ||= ActiveRecord::Base.connection
|
9
|
+
end
|
10
|
+
alias_method :default_connection, :connection
|
11
|
+
|
12
|
+
def with_vanity_connection
|
13
|
+
@connection = Vanity::Adapters::ActiveRecordAdapter::VanityRecord.connection
|
14
|
+
yield
|
15
|
+
@connection = default_connection
|
16
|
+
end
|
17
|
+
|
18
|
+
def change
|
19
|
+
with_vanity_connection do
|
20
|
+
remove_index :vanity_experiments, [:experiment_id]
|
21
|
+
add_index :vanity_experiments, [:experiment_id], :unique => true
|
22
|
+
|
23
|
+
remove_index :vanity_conversions, :name => "by_experiment_id_and_alternative", :unique => true
|
24
|
+
add_index :vanity_conversions, [:vanity_experiment_id, :alternative], :name => "by_experiment_id_and_alternative", :unique => true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "vanity/adapters/active_record_adapter"
|
2
|
+
|
1
3
|
class VanityMigration < ActiveRecord::Migration
|
2
4
|
# Helper methods to ensure we're connecting to the right database, see
|
3
5
|
# https://github.com/assaf/vanity/issues/295.
|
@@ -36,14 +38,14 @@ class VanityMigration < ActiveRecord::Migration
|
|
36
38
|
t.datetime :created_at
|
37
39
|
t.datetime :completed_at
|
38
40
|
end
|
39
|
-
add_index :vanity_experiments, [:experiment_id]
|
41
|
+
add_index :vanity_experiments, [:experiment_id], :unique => true
|
40
42
|
|
41
43
|
create_table :vanity_conversions do |t|
|
42
44
|
t.integer :vanity_experiment_id
|
43
45
|
t.integer :alternative
|
44
46
|
t.integer :conversions
|
45
47
|
end
|
46
|
-
add_index :vanity_conversions, [:vanity_experiment_id, :alternative], :name => "by_experiment_id_and_alternative"
|
48
|
+
add_index :vanity_conversions, [:vanity_experiment_id, :alternative], :name => "by_experiment_id_and_alternative", :unique => true
|
47
49
|
|
48
50
|
create_table :vanity_participants do |t|
|
49
51
|
t.string :experiment_id
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
class Vanity::AddUniqueIndexesGenerator < Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
source_root File.expand_path('../../templates', __FILE__)
|
7
|
+
|
8
|
+
def self.next_migration_number(path)
|
9
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_model_file
|
13
|
+
migration_template "add_unique_indexes_migration.rb", "db/migrate/add_vanity_unique_indexes.rb"
|
14
|
+
end
|
15
|
+
end
|
@@ -19,10 +19,20 @@ module Vanity
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.rails_agnostic_find_or_create_by(method, value)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
retried = false
|
23
|
+
begin
|
24
|
+
if respond_to? :find_or_create_by
|
25
|
+
find_or_create_by(method => value)
|
26
|
+
else
|
27
|
+
send :"find_or_create_by_#{method}", value
|
28
|
+
end
|
29
|
+
rescue ActiveRecord::RecordNotUnique
|
30
|
+
if retried
|
31
|
+
raise
|
32
|
+
else
|
33
|
+
retried = true
|
34
|
+
retry
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
28
38
|
end
|
data/lib/vanity/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vanity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Assaf Arkin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -177,7 +177,9 @@ files:
|
|
177
177
|
- gemfiles/rails42_protected_attributes.gemfile.lock
|
178
178
|
- gemfiles/rails5.gemfile
|
179
179
|
- gemfiles/rails5.gemfile.lock
|
180
|
+
- lib/generators/templates/add_unique_indexes_migration.rb
|
180
181
|
- lib/generators/templates/vanity_migration.rb
|
182
|
+
- lib/generators/vanity/add_unique_indexes_generator.rb
|
181
183
|
- lib/generators/vanity/views_generator.rb
|
182
184
|
- lib/generators/vanity_generator.rb
|
183
185
|
- lib/vanity.rb
|
@@ -290,7 +292,7 @@ metadata: {}
|
|
290
292
|
post_install_message: To get started run vanity --help
|
291
293
|
rdoc_options:
|
292
294
|
- "--title"
|
293
|
-
- Vanity 2.2.
|
295
|
+
- Vanity 2.2.9
|
294
296
|
- "--main"
|
295
297
|
- README.md
|
296
298
|
- "--webcvs"
|