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 CHANGED
@@ -1,4 +1,4 @@
1
- = IWonder (Alpha)
1
+ = IWonder (Beat)
2
2
 
3
3
  Flexible Analytics, and Testing for every corner of your rails application. I read "The Lean Startup" and got inspired. There were a few good solutions, but none of them quite did what I was looking for.
4
4
 
@@ -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 => :sym
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
- test_group = add_to_test_group(randomly_chosen_test_group, current_controller)
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.count
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)
@@ -15,7 +15,7 @@
15
15
  </ul>
16
16
  <% end %>
17
17
 
18
- <% unless Rails.env.production? %>
18
+ <% if Rails.env.development? %>
19
19
  <p>
20
20
  <%= button_to "Create a new ABTest", url_for(:action => :new), :method => :get%>
21
21
  </p>
@@ -1,12 +1,12 @@
1
1
  <div class="show">
2
- <% if Rails.env.production? %>
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>
@@ -5,8 +5,7 @@ module IWonder
5
5
 
6
6
  initializer "i_wonder.loading_tests" do |app|
7
7
 
8
- # can't load if it's migrating the db
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
@@ -1,3 +1,3 @@
1
1
  module IWonder
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -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
+ IWonder::AbTest Load (1.4ms) SELECT "i_wonder_ab_tests".* FROM "i_wonder_ab_tests" WHERE "i_wonder_ab_tests"."sym" = 'unique_sym_1' LIMIT 1
67883
+ WARNING: Can't mass-assign protected attributes: ab_test_goals
67884
+ WARNING: Can't mass-assign protected attributes: type, ab_test_sym
67885
+  (0.1ms) BEGIN
67886
+  (0.4ms) SELECT 1 FROM "i_wonder_ab_tests" WHERE "i_wonder_ab_tests"."name" = 'Unique Test 1' LIMIT 1
67887
+  (0.2ms) SELECT 1 FROM "i_wonder_ab_tests" WHERE "i_wonder_ab_tests"."sym" = 'unique_sym_1' LIMIT 1
67888
+ SQL (3.3ms) INSERT 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" [["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
+ SQL (0.7ms) 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
+  (0.6ms) COMMIT
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