i_wonder 0.0.9 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -1
- data/app/models/i_wonder/ab_test.rb +37 -4
- data/app/models/i_wonder/ab_test_goal.rb +9 -1
- data/app/views/i_wonder/ab_tests/index.html.erb +1 -1
- data/app/views/i_wonder/ab_tests/show.html.erb +3 -3
- data/lib/i_wonder/engine.rb +2 -3
- data/lib/i_wonder/version.rb +1 -1
- data/test/dummy/log/development.log +21 -0
- data/test/dummy/log/test.log +69398 -0
- data/test/factories/ab_test_factory.rb +15 -0
- data/test/functional/ab_controller_mixins_test.rb +20 -6
- data/test/integration/i_wonder/ab_tests_controller_test.rb +46 -0
- data/test/unit/i_wonder/ab_test_test.rb +20 -11
- data/test/unit/i_wonder/loader_test.rb +3 -3
- metadata +26 -22
data/README.rdoc
CHANGED
@@ -6,7 +6,7 @@ module IWonder
|
|
6
6
|
|
7
7
|
has_many :test_group_memberships, :dependent => :destroy, :foreign_key => "ab_test_sym", :primary_key => :sym
|
8
8
|
|
9
|
-
has_many :ab_test_goals, :dependent => :destroy, :foreign_key => "ab_test_sym", :primary_key =>
|
9
|
+
has_many :ab_test_goals, :dependent => :destroy, :foreign_key => "ab_test_sym", :primary_key => "sym"
|
10
10
|
accepts_nested_attributes_for :ab_test_goals, :allow_destroy => true
|
11
11
|
|
12
12
|
hash_accessor :options, :test_group_names, :type => :array, :reject_blanks => true
|
@@ -18,6 +18,31 @@ module IWonder
|
|
18
18
|
validates_uniqueness_of :sym, :on => :create, :message => "must be unique"
|
19
19
|
validates_inclusion_of :test_applies_to, :in => %w( session user account ), :on => :create, :message => "extension %s is not included in the list"
|
20
20
|
|
21
|
+
|
22
|
+
# ----------------------------------------------------------------------------------------------------------------------------------------
|
23
|
+
# These two methods should NOT be needed. For some reason the accepts_nested_attributes_for is not autosaving or deleting associated goals
|
24
|
+
|
25
|
+
def ab_test_goals_attributes=(hash)
|
26
|
+
hash.each{|key,value|
|
27
|
+
goal = self.ab_test_goals.detect{|tg| tg.id == value["id"].to_i}
|
28
|
+
goal ||= self.ab_test_goals.build
|
29
|
+
goal.attributes = value
|
30
|
+
|
31
|
+
if value["_destroy"] =~ /true|1/ or value["_destroy"].is_a?(TrueClass)
|
32
|
+
goal.mark_for_destruction
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
before_save :remove_deleted_test_goals
|
37
|
+
def remove_deleted_test_goals
|
38
|
+
ab_test_goals.select(&:marked_for_destruction?).each(&:destroy)
|
39
|
+
ab_test_goals.each(&:save)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
# ----------------------------------------------------------------------------------------------------------------------------------------
|
44
|
+
|
45
|
+
|
21
46
|
validate :has_two_groups_and_a_goal
|
22
47
|
def has_two_groups_and_a_goal
|
23
48
|
unless test_group_names.length >= 2
|
@@ -30,7 +55,7 @@ module IWonder
|
|
30
55
|
end
|
31
56
|
|
32
57
|
after_save :save_to_file
|
33
|
-
def save_to_file
|
58
|
+
def save_to_file
|
34
59
|
AbTesting::Loader.save_ab_test(self)
|
35
60
|
end
|
36
61
|
|
@@ -47,7 +72,13 @@ module IWonder
|
|
47
72
|
if(current_group = get_current_group(current_controller))
|
48
73
|
return current_group.test_group_name
|
49
74
|
else
|
50
|
-
|
75
|
+
begin
|
76
|
+
test_group = add_to_test_group(randomly_chosen_test_group, current_controller)
|
77
|
+
rescue Exception => e
|
78
|
+
# If there is some error, just return a randome option. Better not to crash
|
79
|
+
# TODO: this should warn developer somehow
|
80
|
+
return randomly_chosen_test_group
|
81
|
+
end
|
51
82
|
return test_group.test_group_name
|
52
83
|
end
|
53
84
|
end
|
@@ -71,7 +102,9 @@ module IWonder
|
|
71
102
|
|
72
103
|
scoped_groups_with_goal_events = ab_test_goal.add_goal_to_query(scoped_groups_with_events)
|
73
104
|
|
74
|
-
scoped_groups_with_goal_events.
|
105
|
+
scoped_groups_with_goal_events = scoped_groups_with_goal_events.select("COUNT(DISTINCT i_wonder_events.#{event_membership_key}) as count_all")
|
106
|
+
|
107
|
+
AbTest.connection.execute(scoped_groups_with_goal_events.to_sql)[0]["count_all"].to_i
|
75
108
|
end
|
76
109
|
|
77
110
|
def from_xml(xml)
|
@@ -14,6 +14,14 @@ module IWonder
|
|
14
14
|
validates_presence_of :event_type, :if => :tracks_event?
|
15
15
|
validates_presence_of :page_view_controller, :if => :tracks_page_view?
|
16
16
|
|
17
|
+
before_validation :clean_up_controller
|
18
|
+
def clean_up_controller
|
19
|
+
if tracks_page_view?
|
20
|
+
page_view_controller.gsub!("Controller", "")
|
21
|
+
page_view_controller.downcase!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
17
25
|
def tracks_event?
|
18
26
|
goal_type == "Event"
|
19
27
|
end
|
@@ -26,7 +34,7 @@ module IWonder
|
|
26
34
|
if tracks_event?
|
27
35
|
sc = scoped_statement.where("i_wonder_events.event_type = ?", event_type)
|
28
36
|
else
|
29
|
-
sc = scoped_statement.where("i_wonder_events.event_type = ? AND controller = ?", "hit", page_view_controller)
|
37
|
+
sc = scoped_statement.where("i_wonder_events.event_type = ? AND i_wonder_events.controller = ?", "hit", page_view_controller)
|
30
38
|
|
31
39
|
if page_view_action.present?
|
32
40
|
sc = sc.where("i_wonder_events.action = ?", page_view_action)
|
@@ -1,12 +1,12 @@
|
|
1
1
|
<div class="show">
|
2
|
-
<% if Rails.env.
|
3
|
-
<span class="description">No Modifying tests in production</span>
|
4
|
-
<% else %>
|
2
|
+
<% if Rails.env.development? %>
|
5
3
|
<p>
|
6
4
|
<%= link_to "Edit", edit_ab_test_path(@ab_test) %>
|
7
5
|
|
|
8
6
|
<%= link_to "Delete", @ab_test, :method => :delete, :confirm => "Are you sure?" %>
|
9
7
|
</p>
|
8
|
+
<% else %>
|
9
|
+
<span class="description">No Modifying tests in production</span>
|
10
10
|
<% end %>
|
11
11
|
|
12
12
|
<h2>I wonder <%= @ab_test.name%>?</h2>
|
data/lib/i_wonder/engine.rb
CHANGED
@@ -5,8 +5,7 @@ module IWonder
|
|
5
5
|
|
6
6
|
initializer "i_wonder.loading_tests" do |app|
|
7
7
|
|
8
|
-
#
|
9
|
-
unless ( File.basename($0) == "rake" && ARGV.include?("db:migrate") )
|
8
|
+
unless File.basename($0) == "rake" # don't run on rake tasks (migration and asset:precompile have cause lot's of problems)
|
10
9
|
ActiveRecord::Base.send :include, HashAccessor # this is to avoid load order issues from a required gem
|
11
10
|
AbTesting::Loader.load_all
|
12
11
|
end
|
@@ -28,7 +27,7 @@ class Railtie < Rails::Railtie
|
|
28
27
|
ApplicationController.send :include, IWonder::Logging::ActionControllerMixins
|
29
28
|
ApplicationController.send :include, IWonder::AbTesting::ActionControllerMixins
|
30
29
|
|
31
|
-
ActiveRecord.send :include, IWonder::Logging::ActiveRecordMixins
|
30
|
+
ActiveRecord::Base.send :include, IWonder::Logging::ActiveRecordMixins
|
32
31
|
end
|
33
32
|
|
34
33
|
end
|
data/lib/i_wonder/version.rb
CHANGED
@@ -67879,3 +67879,24 @@ Served asset /i_wonder/reports.js - 304 Not Modified (0ms)
|
|
67879
67879
|
|
67880
67880
|
Started GET "/assets/i_wonder/application.js?body=1" for 127.0.0.1 at 2011-10-31 11:41:44 -0700
|
67881
67881
|
Served asset /i_wonder/application.js - 304 Not Modified (0ms)
|
67882
|
+
[1m[36mIWonder::AbTest Load (1.4ms)[0m [1mSELECT "i_wonder_ab_tests".* FROM "i_wonder_ab_tests" WHERE "i_wonder_ab_tests"."sym" = 'unique_sym_1' LIMIT 1[0m
|
67883
|
+
WARNING: Can't mass-assign protected attributes: ab_test_goals
|
67884
|
+
WARNING: Can't mass-assign protected attributes: type, ab_test_sym
|
67885
|
+
[1m[35m (0.1ms)[0m BEGIN
|
67886
|
+
[1m[36m (0.4ms)[0m [1mSELECT 1 FROM "i_wonder_ab_tests" WHERE "i_wonder_ab_tests"."name" = 'Unique Test 1' LIMIT 1[0m
|
67887
|
+
[1m[35m (0.2ms)[0m SELECT 1 FROM "i_wonder_ab_tests" WHERE "i_wonder_ab_tests"."sym" = 'unique_sym_1' LIMIT 1
|
67888
|
+
[1m[36mSQL (3.3ms)[0m [1mINSERT INTO "i_wonder_ab_tests" ("created_at", "description", "name", "options", "sym", "test_applies_to", "test_group_data", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"[0m [["created_at", Tue, 01 Nov 2011 01:12:12 UTC +00:00], ["description", nil], ["name", "Unique Test 1"], ["options", "--- \n:test_group_names: \n- Options 1\n- Options 2\n"], ["sym", "unique_sym_1"], ["test_applies_to", "session"], ["test_group_data", "--- {}\n\n"], ["updated_at", Tue, 01 Nov 2011 01:12:12 UTC +00:00]]
|
67889
|
+
[1m[35mSQL (0.7ms)[0m INSERT INTO "i_wonder_ab_test_goals" ("ab_test_sym", "options") VALUES ($1, $2) RETURNING "id" [["ab_test_sym", "unique_sym_1"], ["options", "--- \n:event_type: success\n:goal_type: Event\n"]]
|
67890
|
+
[1m[36m (0.6ms)[0m [1mCOMMIT[0m
|
67891
|
+
PGError: ERROR: column "member_id" does not exist
|
67892
|
+
LINE 1: SELECT DISTINCT(member_id), COUNT(*) FROM "i_wonder_events"
|
67893
|
+
^
|
67894
|
+
: SELECT DISTINCT(member_id), COUNT(*) FROM "i_wonder_events"
|
67895
|
+
PGError: ERROR: column "i_wonder_events.session_id" must appear in the GROUP BY clause or be used in an aggregate function
|
67896
|
+
LINE 1: SELECT DISTINCT(session_id), COUNT(*) FROM "i_wonder_events"...
|
67897
|
+
^
|
67898
|
+
: SELECT DISTINCT(session_id), COUNT(*) FROM "i_wonder_events"
|
67899
|
+
PGError: ERROR: column "i_wonder_events.id" must appear in the GROUP BY clause or be used in an aggregate function
|
67900
|
+
LINE 1: SELECT "i_wonder_events".* FROM "i_wonder_events" GROUP BY ...
|
67901
|
+
^
|
67902
|
+
: SELECT "i_wonder_events".* FROM "i_wonder_events" GROUP BY session_id
|