caboose-cms 0.3.20 → 0.3.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/app/controllers/caboose/ab_options_controller.rb +57 -0
- data/app/controllers/caboose/ab_variants_controller.rb +88 -0
- data/app/controllers/caboose/application_controller.rb +69 -3
- data/app/helpers/caboose/pages_helper.rb +5 -0
- data/app/models/caboose/ab_option.rb +7 -0
- data/app/models/caboose/ab_variant.rb +22 -0
- data/app/models/caboose/core_plugin.rb +6 -2
- data/app/models/caboose/schema.rb +8 -0
- data/app/models/caboose/utilities/schema.rb +8 -2
- data/app/views/caboose/ab_variants/admin_edit.html.erb +99 -0
- data/app/views/caboose/ab_variants/admin_index.html.erb +17 -0
- data/app/views/caboose/ab_variants/admin_new.html.erb +36 -0
- data/config/routes.rb +12 -0
- data/lib/caboose/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MzhlOGU4ZDRlZmYxZGIzODk0Zjk0NDhhM2IwYjM2ZTViMjlmZTA2ZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OWUwZmM5MjdkNmEwNWJkMWIzYjlkN2Q4NTBiMjliZmNkNDM5MzZiNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YjNhYjE1MzU1ZmU4NTQzOWFjMDY5ZmVjM2UwY2NhMzFmNDViMjE0ZTBhY2Ux
|
10
|
+
NDA1ODFiMGQyZGMzNWQ1MTcxZjMxMGI1MjAzZDliYjNlYzdlNWE4YTY4Yzc0
|
11
|
+
OTRmMzkwMmFkODcxYmVkM2I5MzAzMmI1YWU2NDI3NDQwZjJmYWU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZmQ2YTQ4N2Q4M2U3MGJkYWYwNmNhYjczZDU4YTEzZmYwODM2NDBhN2RlMDRm
|
14
|
+
NDBkMGU4ZGJiZDAxMjI2NWRkMGQzMjc2ZTVkOTQ5YTNiYWFkNTMwNjMyNmE5
|
15
|
+
MTg5N2M5Yjc4ZjY3Yjg3Y2FhOTkwMTY5M2Q3NGIxM2UyM2Q1N2Y=
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Caboose
|
2
|
+
class AbOptionsController < ApplicationController
|
3
|
+
layout 'caboose/admin'
|
4
|
+
|
5
|
+
# GET /admin/ab_variants/:variant_id/options
|
6
|
+
def admin_index
|
7
|
+
return unless user_is_allowed_to 'view', 'ab_variants'
|
8
|
+
v = AbVariant.find(params[:variant_id])
|
9
|
+
render :json => v.ab_options
|
10
|
+
end
|
11
|
+
|
12
|
+
# POST admin/ab-variants/:variant_id/options'
|
13
|
+
def admin_create
|
14
|
+
return unless user_is_allowed_to 'edit','ab_variants'
|
15
|
+
|
16
|
+
resp = StdClass.new({
|
17
|
+
'error' => nil,
|
18
|
+
'redirect' => nil
|
19
|
+
})
|
20
|
+
|
21
|
+
opt = AbOption.create(
|
22
|
+
:ab_variant_id => params[:variant_id],
|
23
|
+
:text => params[:text]
|
24
|
+
)
|
25
|
+
resp.redirect = "/admin/ab-variants/#{params[:variant_id]}"
|
26
|
+
render :json => resp
|
27
|
+
end
|
28
|
+
|
29
|
+
# PUT /admin/ab_options/:id
|
30
|
+
def admin_update
|
31
|
+
return unless user_is_allowed_to 'edit', 'ab_variants'
|
32
|
+
|
33
|
+
resp = StdClass.new
|
34
|
+
opt = AbOption.find(params[:id])
|
35
|
+
|
36
|
+
save = true
|
37
|
+
params.each do |k,v|
|
38
|
+
case k
|
39
|
+
when 'text'
|
40
|
+
opt.text = v
|
41
|
+
break
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
resp.success = save && opt.save
|
46
|
+
render :json => resp
|
47
|
+
end
|
48
|
+
|
49
|
+
# DELETE /admin/ab_options/:id
|
50
|
+
def admin_delete
|
51
|
+
return unless user_is_allowed_to 'delete', 'ab_variants'
|
52
|
+
AbOption.find(params[:id]).destroy
|
53
|
+
render :json => true
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Caboose
|
2
|
+
class AbVariantsController < ApplicationController
|
3
|
+
layout 'caboose/admin'
|
4
|
+
|
5
|
+
def before_action
|
6
|
+
@page = Page.page_with_uri('/admin')
|
7
|
+
end
|
8
|
+
|
9
|
+
# GET /admin/ab_variants
|
10
|
+
def admin_index
|
11
|
+
return unless user_is_allowed_to 'view', 'ab_variants'
|
12
|
+
|
13
|
+
@gen = PageBarGenerator.new(params, {'name' => '', 'analytics_name' => ''}, {
|
14
|
+
'model' => 'Caboose::AbVariant',
|
15
|
+
'sort' => 'name',
|
16
|
+
'desc' => 'false',
|
17
|
+
'base_url' => '/admin/ab-variants'
|
18
|
+
})
|
19
|
+
@variants = @gen.items
|
20
|
+
end
|
21
|
+
|
22
|
+
# GET /admin/ab_variants/new
|
23
|
+
def admin_new
|
24
|
+
return unless user_is_allowed_to 'add', 'ab_variants'
|
25
|
+
@variant = AbVariant.new
|
26
|
+
end
|
27
|
+
|
28
|
+
# GET /admin/ab_variants/:id
|
29
|
+
def admin_edit
|
30
|
+
return unless user_is_allowed_to 'edit', 'ab_variants'
|
31
|
+
@variant = AbVariant.find(params[:id])
|
32
|
+
end
|
33
|
+
|
34
|
+
# POST /admin/ab-variants
|
35
|
+
def admin_create
|
36
|
+
return unless user_is_allowed_to 'edit', 'ab_variants'
|
37
|
+
|
38
|
+
resp = StdClass.new({
|
39
|
+
'error' => nil,
|
40
|
+
'redirect' => nil
|
41
|
+
})
|
42
|
+
|
43
|
+
variant = AbVariant.new
|
44
|
+
variant.name = params[:name]
|
45
|
+
variant.analytics_name = params[:name].gsub(' ', '_').downcase
|
46
|
+
|
47
|
+
if (variant.name.length == 0)
|
48
|
+
resp.error = "A name is required."
|
49
|
+
elsif variant.save
|
50
|
+
resp.redirect = "/admin/ab-variants/#{variant.id}"
|
51
|
+
end
|
52
|
+
|
53
|
+
render json: resp
|
54
|
+
end
|
55
|
+
|
56
|
+
# PUT /admin/ab_variants/:id
|
57
|
+
def admin_update
|
58
|
+
return unless user_is_allowed_to 'edit', 'ab_variants'
|
59
|
+
|
60
|
+
resp = StdClass.new
|
61
|
+
variant = AbVariant.find(params[:id])
|
62
|
+
|
63
|
+
save = true
|
64
|
+
params.each do |k,v|
|
65
|
+
case k
|
66
|
+
when 'name'
|
67
|
+
variant.name = v
|
68
|
+
break
|
69
|
+
when 'analytics_name'
|
70
|
+
variant.analytics_name = v
|
71
|
+
break
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
resp.success = save && variant.save
|
76
|
+
render :json => resp
|
77
|
+
end
|
78
|
+
|
79
|
+
# DELETE /admin/ab_variants/:id
|
80
|
+
def admin_destroy
|
81
|
+
return unless user_is_allowed_to 'delete', 'ab_variants'
|
82
|
+
AbVariants.find(params[:id]).destroy
|
83
|
+
resp = StdClass.new('redirect' => '/admin/ab-variants')
|
84
|
+
render :json => resp
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -13,6 +13,7 @@ module Caboose
|
|
13
13
|
@page = Page.page_with_uri(request.fullpath)
|
14
14
|
|
15
15
|
session['use_redirect_urls'] = true if session['use_redirect_urls'].nil?
|
16
|
+
assign_ab_variants
|
16
17
|
|
17
18
|
@crumb_trail = Caboose::Page.crumb_trail(@page)
|
18
19
|
@subnav = {}
|
@@ -23,10 +24,10 @@ module Caboose
|
|
23
24
|
|
24
25
|
# Sets an instance variable of the logged in user
|
25
26
|
@logged_in_user = logged_in_user
|
26
|
-
|
27
|
+
|
27
28
|
before_action
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
# Parses any parameters in the URL and adds them to the params
|
31
32
|
def parse_url_params
|
32
33
|
return if !Caboose.use_url_params
|
@@ -96,6 +97,8 @@ module Caboose
|
|
96
97
|
return session["app_user"]
|
97
98
|
end
|
98
99
|
|
100
|
+
# DEPRECATED: Use user_is_allowed_to(action, resource)
|
101
|
+
#
|
99
102
|
# Checks to see if a user has permission to perform the given action
|
100
103
|
# on the given resource.
|
101
104
|
# Redirects to login if not logged in.
|
@@ -115,7 +118,31 @@ module Caboose
|
|
115
118
|
|
116
119
|
return true
|
117
120
|
end
|
118
|
-
|
121
|
+
|
122
|
+
# Checks to see if a user has permission
|
123
|
+
# to perform action on resource
|
124
|
+
#
|
125
|
+
# Redirects to login if not logged in
|
126
|
+
# Redirects to error page with message if not allowed
|
127
|
+
#
|
128
|
+
# useful for creating super-readable code, for example:
|
129
|
+
# > return unless user_is_allowed_to 'edit', 'pages'
|
130
|
+
# Even your mom could read that code.
|
131
|
+
def user_is_allowed_to(action, resource)
|
132
|
+
unless logged_in?
|
133
|
+
redirect_to "/login?return_url=" + URI.encode(request.fullpath)
|
134
|
+
return false
|
135
|
+
end
|
136
|
+
|
137
|
+
@user = logged_in_user
|
138
|
+
unless @user.is_allowed(resource, action)
|
139
|
+
@error = "You don't have permission to #{action} #{resource}"
|
140
|
+
render :template => "caboose/extras/error"
|
141
|
+
return false
|
142
|
+
end
|
143
|
+
return true
|
144
|
+
end
|
145
|
+
|
119
146
|
# Redirects to login if not logged in.
|
120
147
|
def verify_logged_in
|
121
148
|
if (!logged_in?)
|
@@ -147,5 +174,44 @@ module Caboose
|
|
147
174
|
return "" if v.nil?
|
148
175
|
return v.val
|
149
176
|
end
|
177
|
+
|
178
|
+
#===========================================================================
|
179
|
+
# AB Testing
|
180
|
+
#===========================================================================
|
181
|
+
|
182
|
+
# Sets the ab_variants for the user's session
|
183
|
+
def assign_ab_variants
|
184
|
+
return if session['ab_variants']
|
185
|
+
|
186
|
+
h = {}
|
187
|
+
arr = []
|
188
|
+
AbVariant.find_each do |var|
|
189
|
+
next if var.ab_options.nil? || var.ab_options.count == 0
|
190
|
+
i = rand(var.ab_options.count)
|
191
|
+
h[var.analytics_name] = var.ab_options[i].text
|
192
|
+
arr << "#{var.analytics_name}=#{i+1}"
|
193
|
+
end
|
194
|
+
session['ab_variants'] = h
|
195
|
+
session['ab_variants_analytics_string'] = "|#{arr.join('|')}|"
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get the variant option text for the given variant name.
|
199
|
+
def ab_option_for(analytics_name)
|
200
|
+
assign_ab_variants if session['ab_variants'].nil?
|
201
|
+
return session['ab_variants'][analytics_name] if !session['ab_variants'][analytics_name].nil?
|
202
|
+
|
203
|
+
# Otherwise, add the new variant to the session
|
204
|
+
var = AbVariant.find(:analytics_name => analytics_name).first
|
205
|
+
i = rand(var.ab_options.count)
|
206
|
+
session['ab_variants'][var.analytics_name] = var.ab_options[i].text
|
207
|
+
session['ab_variants_analytics_string'] << "#{var.analytics_name}=#{i+1}|"
|
208
|
+
end
|
209
|
+
|
210
|
+
# Gets the string to be sent to google analytics
|
211
|
+
def analytics_string
|
212
|
+
assign_ab_variants if session['ab_variants_analytics_string'].nil?
|
213
|
+
return "#{session['ab_variants_analytics_string']}"
|
214
|
+
end
|
215
|
+
|
150
216
|
end
|
151
217
|
end
|
@@ -20,5 +20,10 @@ module Caboose
|
|
20
20
|
return str
|
21
21
|
end
|
22
22
|
|
23
|
+
def ab_variants_analytics_code
|
24
|
+
str = session['ab_variants_analytics_string']
|
25
|
+
return "var _gaq = _gaq || [];\n_gaq.push(['_setCustomVar', 1, 'caboose_ab_variants', #{Caboose.json(str)}]);"
|
26
|
+
end
|
27
|
+
|
23
28
|
end
|
24
29
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Class for A-B testing variants. A variant is a set of changes
|
2
|
+
# to the same element on a page. For example, a variant can be used
|
3
|
+
# to change the button text, or images displayed, or even more
|
4
|
+
# complicated behavior
|
5
|
+
class Caboose::AbVariant < ActiveRecord::Base
|
6
|
+
self.table_name = "ab_variants"
|
7
|
+
|
8
|
+
has_many :ab_options, :order => 'id', :dependent => :destroy
|
9
|
+
attr_accessible :name, :analytics_name
|
10
|
+
|
11
|
+
def get_session_option
|
12
|
+
return "" unless self.ab_options
|
13
|
+
opt = self.ab_options.sample
|
14
|
+
return {text: opt.text, id: opt.id}
|
15
|
+
end
|
16
|
+
|
17
|
+
#def random_option
|
18
|
+
# return nil self.ab_options.nil? || self.ab_options.count == 0
|
19
|
+
# return self.ab_options.sample
|
20
|
+
#end
|
21
|
+
|
22
|
+
end
|
@@ -20,12 +20,13 @@ class Caboose::CorePlugin < Caboose::CaboosePlugin
|
|
20
20
|
'text' => 'Settings',
|
21
21
|
'children' => []
|
22
22
|
}
|
23
|
-
|
23
|
+
|
24
24
|
item['children'] << { 'id' => 'users' , 'text' => 'Users' , 'href' => '/admin/users' , 'modal' => false } if user.is_allowed('users' , 'view')
|
25
25
|
item['children'] << { 'id' => 'roles' , 'text' => 'Roles' , 'href' => '/admin/roles' , 'modal' => false } if user.is_allowed('roles' , 'view')
|
26
26
|
item['children'] << { 'id' => 'permissions' , 'text' => 'Permissions' , 'href' => '/admin/permissions' , 'modal' => false } if user.is_allowed('permissions' , 'view')
|
27
|
+
item['children'] << { 'id' => 'blocktypes' , 'text' => 'AB Test Variants' , 'href' => '/admin/ab-variants' , 'modal' => false } if user.is_allowed('abvariants' , 'view')
|
27
28
|
item['children'] << { 'id' => 'variables' , 'text' => 'Variables' , 'href' => '/admin/settings' , 'modal' => false } if user.is_allowed('settings' , 'view')
|
28
|
-
item['children'] << { 'id' => 'blocktypes' , 'text' => 'Page Block Types' , 'href' => '/admin/page-block-types' , 'modal' => false } if user.is_allowed('pageblocktypes' , 'view')
|
29
|
+
item['children'] << { 'id' => 'blocktypes' , 'text' => 'Page Block Types' , 'href' => '/admin/page-block-types' , 'modal' => false } if user.is_allowed('pageblocktypes' , 'view')
|
29
30
|
|
30
31
|
nav << item if item['children'].count > 0
|
31
32
|
|
@@ -39,6 +40,9 @@ class Caboose::CorePlugin < Caboose::CaboosePlugin
|
|
39
40
|
item['children'] << { 'id' => 'posts' , 'text' => 'Posts' , 'href' => '/admin/posts' , 'modal' => false } if user.is_allowed('posts' , 'view')
|
40
41
|
|
41
42
|
nav << item if item['children'].count > 0
|
43
|
+
if user.is_allowed('ab-variants','view')
|
44
|
+
nav << { 'id' => 'ab_variants', 'text' => 'AB Testing', 'href' => '/admin/ab-variants', 'modal' => false }
|
45
|
+
end
|
42
46
|
return nav
|
43
47
|
end
|
44
48
|
|
@@ -143,6 +143,14 @@ class Caboose::Schema < Caboose::Utilities::Schema
|
|
143
143
|
[ :page_id , :integer ],
|
144
144
|
[ :action , :string ]
|
145
145
|
],
|
146
|
+
Caboose::AbVariant => [
|
147
|
+
[ :name , :string ],
|
148
|
+
[ :analytics_name , :string ],
|
149
|
+
],
|
150
|
+
Caboose::AbOption => [
|
151
|
+
[ :text , :string ],
|
152
|
+
[ :ab_variant_id , :integer ]
|
153
|
+
],
|
146
154
|
Caboose::DatabaseSession => [
|
147
155
|
[ :session_id , :string , :null => false ],
|
148
156
|
[ :data , :text ],
|
@@ -45,11 +45,17 @@ class Caboose::Utilities::Schema
|
|
45
45
|
c = ActiveRecord::Base.connection
|
46
46
|
self.schema.each do |model, columns|
|
47
47
|
tbl = model.table_name
|
48
|
-
|
48
|
+
puts "Creating table #{tbl}..."
|
49
49
|
c.create_table tbl if !c.table_exists?(tbl)
|
50
50
|
columns.each do |col|
|
51
|
-
|
51
|
+
puts "Creating column #{tbl}.#{col[0]}..."
|
52
52
|
|
53
|
+
# Special case for attachments
|
54
|
+
if col[1] == :attachment
|
55
|
+
c.add_attachment tbl, col[1] if !c.column_exists?(tbl, "#{col[1]}_file_size")
|
56
|
+
next
|
57
|
+
end
|
58
|
+
|
53
59
|
# Skip if the column exists with the proper data type
|
54
60
|
next if c.column_exists?(tbl, col[0], col[1])
|
55
61
|
|
@@ -0,0 +1,99 @@
|
|
1
|
+
<h1>Editing AB Test Variant</h1>
|
2
|
+
|
3
|
+
<div id="abvariant_<%= @variant.id %>_name"></div>
|
4
|
+
<div id="abvariant_<%= @variant.id %>_analytics_name"></div>
|
5
|
+
|
6
|
+
<p>Google analytics search term: <code>caboose_ab_variants="*|<%= @variant.analytics_name %>=1|*"</code></p>
|
7
|
+
<h2>Options</h2>
|
8
|
+
<% if @variant.ab_options && @variant.ab_options.count > 0 %>
|
9
|
+
<table>
|
10
|
+
<% @variant.ab_options.each do |opt| %>
|
11
|
+
<tr>
|
12
|
+
<td><div id="aboption_<%= opt.id %>_text"></div></td>
|
13
|
+
<td><input type='button' value='Delete' onclick="delete_option(<%= opt.id %>);" /></td>
|
14
|
+
</tr>
|
15
|
+
<% end %>
|
16
|
+
</table>
|
17
|
+
<% else %>
|
18
|
+
<p>This variant doesn't have any options.</p>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<div id="message"></div>
|
22
|
+
<p>
|
23
|
+
<input type='button' value='Back' onclick="window.location='/admin/ab-variants';" >
|
24
|
+
<input type='button' value='Add New Option' onclick="add_option();" >
|
25
|
+
</p>
|
26
|
+
|
27
|
+
<% content_for :caboose_js do %>
|
28
|
+
<%= javascript_include_tag "caboose/model/all" %>
|
29
|
+
<script type="text/javascript">
|
30
|
+
|
31
|
+
function delete_option(option_id, confirm)
|
32
|
+
{
|
33
|
+
if (!confirm)
|
34
|
+
{
|
35
|
+
var p = $('<p/>').addClass('note warning')
|
36
|
+
.append("Are you sure you want to delete the option? ")
|
37
|
+
.append($('<input/>').attr('type','button').val('Yes').click(function() { delete_option(option_id, true); })).append(' ')
|
38
|
+
.append($('<input/>').attr('type','button').val('No').click(function() { $('#message').empty(); }));
|
39
|
+
$('#message').empty().append(p);
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
$('#message').empty().html($('<p/>').addClass('loading').html("Deleting option..."));
|
43
|
+
$.ajax({
|
44
|
+
url: '/admin/ab-options/' + option_id,
|
45
|
+
type: 'delete',
|
46
|
+
success: function(resp) {
|
47
|
+
if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
|
48
|
+
else window.location.reload(true);
|
49
|
+
}
|
50
|
+
});
|
51
|
+
}
|
52
|
+
|
53
|
+
function add_option() {
|
54
|
+
$('#message').html("<p class='loading'>Adding new A/B Option...</p>");
|
55
|
+
$.ajax({
|
56
|
+
url: '/admin/ab-variants/<%= @variant.id %>/options',
|
57
|
+
type: 'post',
|
58
|
+
data: {
|
59
|
+
text: ""
|
60
|
+
},
|
61
|
+
success: function(resp) {
|
62
|
+
if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
|
63
|
+
if (resp.redirect) window.location.reload(true);
|
64
|
+
}
|
65
|
+
});
|
66
|
+
}
|
67
|
+
|
68
|
+
$(document).ready(function() {
|
69
|
+
|
70
|
+
m = new ModelBinder({
|
71
|
+
name: 'abvariant',
|
72
|
+
id: <%= @variant.id %>,
|
73
|
+
update_url: '/admin/ab-variants/<%= @variant.id %>',
|
74
|
+
authenticity_token: '<%= form_authenticity_token %>',
|
75
|
+
attributes: [
|
76
|
+
{ name: 'name' , nice_name: 'Variant Name' , type: 'text', value: <%= raw Caboose.json(@variant.name) %> , width: 800 },
|
77
|
+
{ name: 'analytics_name' , nice_name: 'Google Analytics Name' , type: 'text', value: <%= raw Caboose.json(@variant.analytics_name) %> , width: 800 }
|
78
|
+
]
|
79
|
+
});
|
80
|
+
|
81
|
+
<% if @variant.ab_options && @variant.ab_options.count > 0 %>
|
82
|
+
<% i = 1 %>
|
83
|
+
<% @variant.ab_options.each do |opt| %>
|
84
|
+
m = new ModelBinder({
|
85
|
+
name: 'aboption',
|
86
|
+
id: <%= opt.id %>,
|
87
|
+
update_url: '/admin/ab-options/<%= opt.id %>',
|
88
|
+
authenticity_token: '<%= form_authenticity_token %>',
|
89
|
+
attributes: [
|
90
|
+
{ name: 'text', nice_name: 'Option <%= i %>', type: 'text', value: <%= raw Caboose.json(opt.text) %> , width: 800 }
|
91
|
+
]
|
92
|
+
});
|
93
|
+
<% i = i + 1 %>
|
94
|
+
<% end %>
|
95
|
+
<% end %>
|
96
|
+
});
|
97
|
+
|
98
|
+
</script>
|
99
|
+
<% end %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h1>A/B Test Variants</h1>
|
2
|
+
|
3
|
+
<p><a href='/admin/ab-variants/new'>New Variant</a></p>
|
4
|
+
<% if (@variants.count > 0) %>
|
5
|
+
<table class='data'>
|
6
|
+
<tr><%= raw @gen.sortable_table_headings({'name' => 'Variant Name', 'analytics_name' => 'Analytics Name'}) %></tr>
|
7
|
+
<% @variants.each do |v| %>
|
8
|
+
<tr onclick="window.location='/admin/ab-variants/<%= v.id %>';">
|
9
|
+
<td><%= v.name %></td>
|
10
|
+
<td><%= v.analytics_name %></td>
|
11
|
+
</tr>
|
12
|
+
<% end %>
|
13
|
+
</table>
|
14
|
+
<p><%= raw @gen.generate %></p>
|
15
|
+
<% else %>
|
16
|
+
<p>No A/B variants found.</p>
|
17
|
+
<% end %>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<h1>New AB Test</h1>
|
2
|
+
|
3
|
+
<form action='/admin/ab-variants' method='post' id='ab_variant_form'>
|
4
|
+
<input type='hidden' name='authenticity_token' value='<%=form_authenticity_token %>'>
|
5
|
+
<p><input type='text' name='name' id='name' placeholder='AB Variant Name' style='width: 500px;'></p>
|
6
|
+
<div id='message'></div>
|
7
|
+
<p>
|
8
|
+
<input type='button' value='< Back' onclick="window.location='/admin/ab-variants';">
|
9
|
+
<input type='submit' value='Add New A/B Variant' onclick="add_ab_variant(); return false;">
|
10
|
+
</p>
|
11
|
+
</form>
|
12
|
+
|
13
|
+
<% content_for :caboose_js do %>
|
14
|
+
<script type='text/javascript'>
|
15
|
+
|
16
|
+
function add_ab_variant()
|
17
|
+
{
|
18
|
+
$('#message').html("<p class='loading'>Adding A/B Variant...</p>");
|
19
|
+
$.ajax({
|
20
|
+
url: '/admin/ab-variants',
|
21
|
+
type: 'post',
|
22
|
+
data: $('#ab_variant_form').serialize(),
|
23
|
+
success: function(resp) {
|
24
|
+
if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
|
25
|
+
if (resp.redirect) window.location = resp.redirect;
|
26
|
+
}
|
27
|
+
});
|
28
|
+
}
|
29
|
+
|
30
|
+
var modal = false;
|
31
|
+
$(window).load(function() {
|
32
|
+
modal = new CabooseModal(800);
|
33
|
+
});
|
34
|
+
|
35
|
+
</script>
|
36
|
+
<% end %>
|
data/config/routes.rb
CHANGED
@@ -115,6 +115,18 @@ Caboose::Engine.routes.draw do
|
|
115
115
|
get "admin/posts" => "posts#admin_index"
|
116
116
|
post "admin/posts" => "posts#admin_add"
|
117
117
|
delete "admin/posts/:id" => "posts#admin_delete"
|
118
|
+
|
119
|
+
get "admin/ab-variants" => "ab_variants#admin_index"
|
120
|
+
get "admin/ab-variants/new" => "ab_variants#admin_new"
|
121
|
+
get "admin/ab-variants/:id" => "ab_variants#admin_edit"
|
122
|
+
put "admin/ab-variants/:id" => "ab_variants#admin_update"
|
123
|
+
post "admin/ab-variants" => "ab_variants#admin_create"
|
124
|
+
delete "admin/ab-variants/:id" => "ab_variants#admin_delete"
|
125
|
+
|
126
|
+
get "admin/ab-variants/:variant_id/options" => "ab_options#admin_index"
|
127
|
+
put "admin/ab-options/:id" => "ab_options#admin_update"
|
128
|
+
post "admin/ab-variants/:variant_id/options" => "ab_options#admin_create"
|
129
|
+
delete "admin/ab-options/:id" => "ab_options#admin_delete"
|
118
130
|
|
119
131
|
match '*path' => 'pages#show'
|
120
132
|
root :to => 'pages#show'
|
data/lib/caboose/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: caboose-cms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Barry
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -166,6 +166,8 @@ files:
|
|
166
166
|
- app/assets/stylesheets/caboose/station_modal.css
|
167
167
|
- app/assets/stylesheets/caboose/station_sidebar.css
|
168
168
|
- app/assets/stylesheets/caboose/tinymce.css
|
169
|
+
- app/controllers/caboose/ab_options_controller.rb
|
170
|
+
- app/controllers/caboose/ab_variants_controller.rb
|
169
171
|
- app/controllers/caboose/admin_controller.rb
|
170
172
|
- app/controllers/caboose/application_controller.rb
|
171
173
|
- app/controllers/caboose/login_controller.rb
|
@@ -186,6 +188,8 @@ files:
|
|
186
188
|
- app/helpers/caboose/pages_helper.rb
|
187
189
|
- app/helpers/caboose/permissions_helper.rb
|
188
190
|
- app/helpers/caboose/products_helper.rb
|
191
|
+
- app/models/caboose/ab_option.rb
|
192
|
+
- app/models/caboose/ab_variant.rb
|
189
193
|
- app/models/caboose/approval_request.rb
|
190
194
|
- app/models/caboose/asset.rb
|
191
195
|
- app/models/caboose/authenticator.rb
|
@@ -221,6 +225,9 @@ files:
|
|
221
225
|
- app/models/caboose/std_class.rb
|
222
226
|
- app/models/caboose/user.rb
|
223
227
|
- app/models/caboose/utilities/schema.rb
|
228
|
+
- app/views/caboose/ab_variants/admin_edit.html.erb
|
229
|
+
- app/views/caboose/ab_variants/admin_index.html.erb
|
230
|
+
- app/views/caboose/ab_variants/admin_new.html.erb
|
224
231
|
- app/views/caboose/admin/index.html.erb
|
225
232
|
- app/views/caboose/application/show.html.erb
|
226
233
|
- app/views/caboose/extras/error.html.erb
|