forked from assaf/vanity
/
helpers.rb
110 lines (107 loc) · 3.49 KB
/
helpers.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
module Vanity
# Helper methods for use in your controllers.
#
# 1) Use Vanity from within your controller:
#
# class ApplicationController < ActionController::Base
# use_vanity :current_user end
# end
#
# 2) Present different options for an A/B test:
#
# Get started for only $<%= ab_test :pricing %> a month!
#
# 3) Measure conversion:
#
# def signup
# track! :pricing
# . . .
# end
module Rails
module ClassMethods
# Defines the vanity_identity method and the set_identity_context filter.
#
# Call with the name of a method that returns an object whose identity
# will be used as the Vanity identity. Confusing? Let's try by example:
#
# class ApplicationController < ActionController::Base
# use_vanity :current_user
#
# def current_user
# User.find(session[:user_id])
# end
# end
#
# If that method (current_user in this example) returns nil, Vanity will
# set the identity for you (using a cookie to remember it across
# requests). It also uses this mechanism if you don't provide an
# identity object, by calling use_vanity with no arguments.
#
# Of course you can also use a block:
# class ProjectController < ApplicationController
# use_vanity { |controller| controller.params[:project_id] }
# end
def use_vanity(symbol = nil, &block)
define_method :vanity_identity do
return @vanity_identity if @vanity_identity
if block
@vanity_identity = block.call(self)
elsif symbol && object = send(symbol)
@vanity_identity = object.id
elsif response # everyday use
@vanity_identity = cookies["vanity_id"] || OpenSSL::Random.random_bytes(16).unpack("H*")[0]
cookies["vanity_id"] = { value: @vanity_identity, expires: 1.month.from_now }
@vanity_identity
else # during functional testing
@vanity_identity = "test"
end
end
define_method :set_vanity_context do
Vanity.context = self
end
before_filter :set_vanity_context
before_filter { Vanity.playground.reload! } unless ::Rails.configuration.cache_classes
end
end
# This method returns one of the alternative values in the named A/B test.
#
# Examples using ab_test inside controller:
# def index
# if ab_test(:new_page) # true/false test
# render action: "new_page"
# else
# render action: "index"
# end
# end
#
# def index
# render action: ab_test(:new_page) # alternatives are page names
# end
#
# Examples using ab_test inside view:
# <%= if ab_test(:banner) %>100% less complexity!<% end %>
#
# <%= ab_test(:greeting) %> <%= current_user.name %>
#
# <% ab_test :features do |count| %>
# <%= count %> features to choose from!
# <% end %>
def ab_test(name, &block)
value = Vanity.playground.experiment(name).choose
if block
content = capture(value, &block)
block_called_from_erb?(block) ? concat(content) : content
else
value
end
end
# This method records conversion on the named A/B test. For example:
# def create
# track! :call_to_action
# Acccount.create! params[:account]
# end
def track!(name)
Vanity.playground.track! name
end
end
end