easy_ab 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -6
- data/app/models/easy_ab/grouping.rb +7 -1
- data/lib/easy_ab/experiment.rb +23 -17
- data/lib/easy_ab/helpers.rb +33 -6
- data/lib/easy_ab/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 068d106a909b0229bc7fc28960f275fca34bd5e9
|
4
|
+
data.tar.gz: 411b8a8f520e4d4f1dd627065e1105b08175acee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4429ad954dcf221b315d43766c04446e72ee1bb21cef672510e1aebd17214d9224b0a20fa0af06755f52e8818c6da1f1cca317827085fe8c6b03ee956701cb8f
|
7
|
+
data.tar.gz: 01924f52c1e3a40dde96fcfee2bf8e5d39b79b2f16df5b8c55a4a51e71e471ae60984a2452a06a8e6b51d03654c6d1e3ee539db45a141219b91a742e0e600916
|
data/CHANGELOG.md
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# 0.4.0 (2017-08-16)
|
2
|
+
- You can specify user in `ab_test()` This useful when requests do not contain current_user. A well-known example is controllers which handle payment results by listening requests from 3rd party payment gateway.
|
3
|
+
|
4
|
+
# 0.3.0 (2017-08-16)
|
5
|
+
- Supports scope in config to define whether a user can join an experiment or not.
|
3
6
|
|
4
7
|
# 0.2.0 (2017-08-15)
|
5
|
-
|
8
|
+
- **API change**: If all rules failed, `ab_test` returns nil, instead of the first variant.
|
6
9
|
|
7
10
|
# 0.1.0
|
8
|
-
|
11
|
+
- Support winner
|
9
12
|
|
10
13
|
# 0.0.3
|
11
|
-
|
14
|
+
- Add new API `all_participated_experiments` to list current user's all participated experiments
|
12
15
|
|
13
16
|
# 0.0.1
|
14
|
-
|
17
|
+
- The first version :)
|
@@ -5,7 +5,7 @@ module EasyAb
|
|
5
5
|
validates :experiment, presence: true
|
6
6
|
validates :variant, presence: true
|
7
7
|
validates :user_id, uniqueness: { scope: [:experiment] }
|
8
|
-
|
8
|
+
validate :cookie_should_be_unique_when_user_id_is_nil
|
9
9
|
validate :user_should_be_present
|
10
10
|
|
11
11
|
private
|
@@ -16,5 +16,11 @@ module EasyAb
|
|
16
16
|
errors.add(:cookie, "or user_id can't be blank")
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def cookie_should_be_unique_when_user_id_is_nil
|
21
|
+
if user_id.nil?
|
22
|
+
errors.add(:cookie, "already exists") if self.class.where(cookie: cookie, user_id: nil).exists?
|
23
|
+
end
|
24
|
+
end
|
19
25
|
end
|
20
26
|
end
|
data/lib/easy_ab/experiment.rb
CHANGED
@@ -64,29 +64,35 @@ module EasyAb
|
|
64
64
|
grouping.variant
|
65
65
|
end
|
66
66
|
|
67
|
+
# TODO: add spec
|
67
68
|
def find_grouping_by_user_recognition(user_recognition)
|
68
|
-
user_id
|
69
|
-
cookie
|
69
|
+
user_id = user_recognition[:id].presence
|
70
|
+
cookie = user_recognition[:cookie].presence
|
71
|
+
raise 'User not found: both user_id and cookie are empty' if user_id.nil? && cookie.nil?
|
72
|
+
|
73
|
+
# Cases should take into consideration
|
74
|
+
# Case I: user participated experiment with login and return again
|
75
|
+
# Case II: user participated experiment with login and return by another device with login
|
76
|
+
# Case III: user participated experiment with login and return by the same device, but cookie was cleared between last and this participation
|
77
|
+
# => Both II and III already exist a record with the same user_id but different cookie
|
78
|
+
# In the above two cases, we update the cookie of the exising record
|
79
|
+
#
|
80
|
+
# Case IV: User participated experiment without login and return with login
|
81
|
+
# => Assign user_id to the existing record
|
82
|
+
#
|
83
|
+
# Case V: User participated experiment without login and return without login, too
|
70
84
|
grouping = nil
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
if user_id # If user login
|
75
|
-
# Case I: User participated experiment with login and return again
|
76
|
-
# Case II: user participated experiment with login and return by another device with login
|
77
|
-
# Case III: user participated experiment with login and return by the same device, but cookie was cleared between last and this participation
|
78
|
-
# => Both II and III already exist a record with the same user_id but different cookie
|
79
|
-
# In the above two cases, we update the cookie of the exising record
|
85
|
+
if user_id # User is signed in
|
86
|
+
# Case I, II, III
|
80
87
|
return grouping if (grouping = groupings.where(user_id: user_id).first) && ((cookie && grouping.cookie = cookie) || true)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
88
|
+
# Case IV
|
89
|
+
return grouping if (cookie && grouping = groupings.where(user_id: nil, cookie: cookie).first) && ((grouping.user_id = user_id) || true) # Assign user_id
|
90
|
+
elsif cookie # User is not signed in
|
91
|
+
# Case V
|
85
92
|
return grouping if grouping = groupings.where(cookie: cookie).first
|
86
93
|
end
|
87
94
|
|
88
|
-
|
89
|
-
nil
|
95
|
+
grouping
|
90
96
|
end
|
91
97
|
|
92
98
|
def groupings
|
data/lib/easy_ab/helpers.rb
CHANGED
@@ -7,7 +7,7 @@ module EasyAb
|
|
7
7
|
|
8
8
|
if respond_to?(:request) && params[:ab_test] && params[:ab_test][experiment_name]
|
9
9
|
# Check current user is admin or not by proc defined by gem user
|
10
|
-
if
|
10
|
+
if easy_ab_user_is_admin?(options)
|
11
11
|
options[:variant] ||= params[:ab_test][experiment_name]
|
12
12
|
end
|
13
13
|
# TODO: exclude bot
|
@@ -15,21 +15,23 @@ module EasyAb
|
|
15
15
|
|
16
16
|
experiment = EasyAb::Experiment.find_by_name!(experiment_name)
|
17
17
|
|
18
|
-
# Obtain context
|
18
|
+
# Obtain context for rules
|
19
19
|
if experiment.rules.present?
|
20
20
|
@rules_with_current_context ||= experiment.rules.map { |rule| Proc.new { instance_exec(&rule)} }
|
21
21
|
options[:contexted_rules] = @rules_with_current_context
|
22
22
|
end
|
23
23
|
|
24
|
-
# Obtain context
|
24
|
+
# Obtain context for scope
|
25
25
|
if experiment.scope.present?
|
26
26
|
@scope ||= Proc.new { instance_exec(&experiment.scope) }
|
27
27
|
options[:scope] = @scope
|
28
28
|
end
|
29
29
|
|
30
30
|
@variant_cache ||= {}
|
31
|
-
@variant_cache[
|
32
|
-
|
31
|
+
@variant_cache[easy_ab_user_id(options)] ||= {}
|
32
|
+
@variant_cache[easy_ab_user_id(options)][experiment_name] ||= experiment.assign_variant(user_recognition, options)
|
33
|
+
variant = @variant_cache[easy_ab_user_id(options)][experiment_name]
|
34
|
+
block_given? ? yield(variant) : variant
|
33
35
|
end
|
34
36
|
|
35
37
|
# Return all participated experiments and the corresponding variants for current user
|
@@ -62,21 +64,46 @@ module EasyAb
|
|
62
64
|
# TODO:
|
63
65
|
# return (raise NotImplementedError) if options[:user] && (users << options[:user])
|
64
66
|
|
65
|
-
|
67
|
+
# if options[:user] && options[:user].id
|
68
|
+
# user_recognition[:id] = options[:user].id
|
69
|
+
# else
|
70
|
+
# user_recognition[:id] = current_user_id if current_user_signed_in?
|
71
|
+
# end
|
72
|
+
|
73
|
+
user_recognition[:id] = easy_ab_user_id(options)
|
74
|
+
|
66
75
|
# Controllers and views
|
67
76
|
user_recognition[:cookie] = find_or_create_easy_ab_cookie if respond_to?(:request)
|
68
77
|
|
69
78
|
user_recognition
|
70
79
|
end
|
71
80
|
|
81
|
+
def easy_ab_user_signed_in?
|
82
|
+
current_user_signed_in?
|
83
|
+
end
|
84
|
+
|
72
85
|
def current_user_signed_in?
|
73
86
|
user_signed_in_method_proc.call
|
74
87
|
end
|
75
88
|
|
89
|
+
def easy_ab_user_id(options)
|
90
|
+
if options[:user]
|
91
|
+
options[:user].id
|
92
|
+
elsif easy_ab_user_signed_in?
|
93
|
+
current_user_id
|
94
|
+
else
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
76
99
|
def current_user_id
|
77
100
|
current_user_id_proc.call
|
78
101
|
end
|
79
102
|
|
103
|
+
def easy_ab_user_is_admin?(options)
|
104
|
+
options[:user] ? false : current_user_is_admin?
|
105
|
+
end
|
106
|
+
|
80
107
|
def current_user_is_admin?
|
81
108
|
authorize_admin_with_proc.call
|
82
109
|
end
|
data/lib/easy_ab/version.rb
CHANGED