Commit d97fd2d2701ee84323db08bfda360aae800cb19c

Authored by Dhruv Kapadia
1 parent 05ae50f0

Adding visitor_votes and visitor_ideas to all vote reponses

app/controllers/choices_controller.rb
@@ -60,8 +60,11 @@ class ChoicesController < InheritedResources::Base @@ -60,8 +60,11 @@ class ChoicesController < InheritedResources::Base
60 60
61 @question = Question.find params[:question_id] 61 @question = Question.find params[:question_id]
62 62
  63 + visitor_identifier = params['params']['auto']
  64 + visitor = current_user.visitors.find_or_create_by_identifier(visitor_identifier)
  65 +
63 respond_to do |format| 66 respond_to do |format|
64 - if @choice = current_user.create_choice(params['params']['auto'], @question, {:data => params['params']['data'], 67 + if @choice = current_user.create_choice(visitor_identifier, @question, {:data => params['params']['data'],
65 :local_identifier => params['params']['local_identifier']}) 68 :local_identifier => params['params']['local_identifier']})
66 saved_choice_id = Proc.new { |options| options[:builder].tag!('saved_choice_id', @choice.id) } 69 saved_choice_id = Proc.new { |options| options[:builder].tag!('saved_choice_id', @choice.id) }
67 choice_status = Proc.new { |options| 70 choice_status = Proc.new { |options|
@@ -71,7 +74,10 @@ class ChoicesController < InheritedResources::Base @@ -71,7 +74,10 @@ class ChoicesController < InheritedResources::Base
71 74
72 Question.update_counters(@question.id, :inactive_choices_count => @choice.active? ? 0 : 1) 75 Question.update_counters(@question.id, :inactive_choices_count => @choice.active? ? 0 : 1)
73 76
74 - format.xml { render :xml => @choice.to_xml(:procs => [saved_choice_id, choice_status]), :status => :ok } 77 + visitor_votes = Proc.new { |options| options[:builder].tag!('visitor_votes', visitor.votes.count(:conditions => {:question_id => @question.id})) }
  78 + visitor_ideas = Proc.new { |options| options[:builder].tag!('visitor_ideas', visitor.items.count) }
  79 +
  80 + format.xml { render :xml => @choice.to_xml(:procs => [saved_choice_id, choice_status, visitor_votes, visitor_ideas]), :status => :ok }
75 # format.xml { render :xml => @question.picked_prompt.to_xml(:methods => [:left_choice_text, :right_choice_text], :procs => [saved_choice_id, choice_status]), :status => :ok } 81 # format.xml { render :xml => @question.picked_prompt.to_xml(:methods => [:left_choice_text, :right_choice_text], :procs => [saved_choice_id, choice_status]), :status => :ok }
76 format.json { render :json => @question.to_json(:procs => [saved_choice_id, choice_status]), :status => :ok } 82 format.json { render :json => @question.to_json(:procs => [saved_choice_id, choice_status]), :status => :ok }
77 else 83 else
app/controllers/prompts_controller.rb
@@ -84,12 +84,16 @@ class PromptsController < InheritedResources::Base @@ -84,12 +84,16 @@ class PromptsController < InheritedResources::Base
84 end 84 end
85 85
86 86
87 - @a = current_user.record_appearance(visitor_identifier, next_prompt) 87 + visitor = current_user.visitors.find_or_create_by_identifier(visitor_identifier)
  88 + @a = current_user.record_appearance(visitor, next_prompt)
88 89
89 appearance_id = Proc.new { |options| options[:builder].tag!('appearance_id', @a.lookup) } 90 appearance_id = Proc.new { |options| options[:builder].tag!('appearance_id', @a.lookup) }
  91 +
  92 + visitor_votes = Proc.new { |options| options[:builder].tag!('visitor_votes', visitor.votes.count(:conditions => {:question_id => @question.id})) }
  93 + visitor_ideas = Proc.new { |options| options[:builder].tag!('visitor_ideas', visitor.items.count) }
90 94
91 - format.xml { render :xml => next_prompt.to_xml(:procs => [appearance_id], :methods => [:left_choice_text, :right_choice_text, :left_choice_id, :right_choice_id]), :status => :ok }  
92 - format.json { render :json => next_prompt.to_json(:procs => [appearance_id], :methods => [:left_choice_text, :right_choice_text, :left_choice_id, :right_choice_id]), :status => :ok } 95 + format.xml { render :xml => next_prompt.to_xml(:procs => [appearance_id, visitor_votes, visitor_ideas], :methods => [:left_choice_text, :right_choice_text, :left_choice_id, :right_choice_id]), :status => :ok }
  96 + format.json { render :json => next_prompt.to_json(:procs => [appearance_id, visitor_votes, visitor_ideas], :methods => [:left_choice_text, :right_choice_text, :left_choice_id, :right_choice_id]), :status => :ok }
93 else 97 else
94 format.xml { render :xml => c, :status => :unprocessable_entity } 98 format.xml { render :xml => c, :status => :unprocessable_entity }
95 format.json { render :json => c, :status => :unprocessable_entity } 99 format.json { render :json => c, :status => :unprocessable_entity }
app/controllers/questions_controller.rb
@@ -74,7 +74,8 @@ class QuestionsController < InheritedResources::Base @@ -74,7 +74,8 @@ class QuestionsController < InheritedResources::Base
74 # we sometimes request a question when no prompt is displayed 74 # we sometimes request a question when no prompt is displayed
75 # TODO It would be a good idea to find these places and treat them like barebones 75 # TODO It would be a good idea to find these places and treat them like barebones
76 if !visitor_identifier.blank? 76 if !visitor_identifier.blank?
77 - @a = current_user.record_appearance(visitor_identifier, @p) 77 + visitor = current_user.visitors.find_or_create_by_identifier(visitor_identifier)
  78 + @a = current_user.record_appearance(visitor, @p)
78 logger.info("creating appearance!") 79 logger.info("creating appearance!")
79 else 80 else
80 @a = nil 81 @a = nil
@@ -85,10 +86,15 @@ class QuestionsController < InheritedResources::Base @@ -85,10 +86,15 @@ class QuestionsController < InheritedResources::Base
85 picked_prompt_id = Proc.new { |options| options[:builder].tag!('picked_prompt_id', @p.id) } 86 picked_prompt_id = Proc.new { |options| options[:builder].tag!('picked_prompt_id', @p.id) }
86 appearance_id = Proc.new { |options| options[:builder].tag!('appearance_id', @a.lookup) } 87 appearance_id = Proc.new { |options| options[:builder].tag!('appearance_id', @a.lookup) }
87 88
  89 + visitor_votes = Proc.new { |options| options[:builder].tag!('visitor_votes', visitor.votes.count(:conditions => {:question_id => @question.id})) }
  90 + visitor_ideas = Proc.new { |options| options[:builder].tag!('visitor_ideas', visitor.items.count) }
  91 +
88 the_procs = [left_choice_text, right_choice_text, picked_prompt_id] 92 the_procs = [left_choice_text, right_choice_text, picked_prompt_id]
89 93
90 if @a 94 if @a
91 the_procs << appearance_id 95 the_procs << appearance_id
  96 + the_procs << visitor_votes
  97 + the_procs << visitor_ideas
92 end 98 end
93 99
94 show! do |format| 100 show! do |format|
app/models/user.rb
@@ -39,9 +39,7 @@ class User &lt; ActiveRecord::Base @@ -39,9 +39,7 @@ class User &lt; ActiveRecord::Base
39 #prompt.choices.each {|c| c.compute_score; c.save!} 39 #prompt.choices.each {|c| c.compute_score; c.save!}
40 end 40 end
41 41
42 - def record_appearance(visitor_identifier, prompt)  
43 - visitor = visitors.find_or_create_by_identifier(visitor_identifier)  
44 - 42 + def record_appearance(visitor, prompt)
45 a = Appearance.create(:voter => visitor, :prompt => prompt, :question_id => prompt.question_id, 43 a = Appearance.create(:voter => visitor, :prompt => prompt, :question_id => prompt.question_id,
46 :lookup => Digest::MD5.hexdigest(rand(10000000000).to_s + visitor.id.to_s + prompt.id.to_s) ) 44 :lookup => Digest::MD5.hexdigest(rand(10000000000).to_s + visitor.id.to_s + prompt.id.to_s) )
47 end 45 end
db/migrate/20100423154040_add_vistor_index_to_votes_table.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +class AddVistorIndexToVotesTable < ActiveRecord::Migration
  2 + def self.up
  3 + add_index :votes, :voter_id
  4 + add_index :items, :creator_id
  5 + end
  6 +
  7 + def self.down
  8 + remove_index :votes, :voter_id
  9 + remove_index :items, :creator_id
  10 + end
  11 +end
spec/controllers/questions_controller_spec.rb
@@ -24,6 +24,10 @@ describe QuestionsController do @@ -24,6 +24,10 @@ describe QuestionsController do
24 def mock_appearance(stubs={}) 24 def mock_appearance(stubs={})
25 @mock_appearance||= mock_model(Appearance, stubs) 25 @mock_appearance||= mock_model(Appearance, stubs)
26 end 26 end
  27 +
  28 + def mock_visitor(stubs={})
  29 + @mock_visitor||= mock_model(Visitor, stubs)
  30 + end
27 # 31 #
28 # describe "GET index" do 32 # describe "GET index" do
29 # it "assigns all questions as @questions" do 33 # it "assigns all questions as @questions" do
@@ -39,26 +43,80 @@ describe QuestionsController do @@ -39,26 +43,80 @@ describe QuestionsController do
39 mock_question.stub!(:picked_prompt).and_return(mock_prompt) 43 mock_question.stub!(:picked_prompt).and_return(mock_prompt)
40 end 44 end
41 45
  46 +
42 it "assigns the requested question as @question" do 47 it "assigns the requested question as @question" do
43 Question.stub!(:find).with("37").and_return(mock_question) 48 Question.stub!(:find).with("37").and_return(mock_question)
44 #TODO it shouldn't call this unless we are generating an appearance, right? 49 #TODO it shouldn't call this unless we are generating an appearance, right?
45 50
46 get :show, :id => "37" 51 get :show, :id => "37"
47 assigns[:question].should equal(mock_question) 52 assigns[:question].should equal(mock_question)
48 - assigns[:prompt].should equal(mock_prompt) 53 + assigns[:p].should equal(mock_prompt)
49 assigns[:a].should be_nil 54 assigns[:a].should be_nil
50 end 55 end
51 56
52 - #TODO this is not a particularly intutive param to pass in order to create an appearance  
53 - it "creates an appearance when a visitor identifier is a param" do  
54 - @user.stub!(:record_appearance).with("somelongunique32charstring", mock_prompt).and_return(mock_appearance)  
55 - get :show, :id => "37", :visitor_identifier => "somelongunique32charstring" 57 +
  58 + it "does not create an appearance when the 'barebones' param is set" do
  59 + get :show, :id => "37", :barebones => true
56 assigns[:question].should equal(mock_question) 60 assigns[:question].should equal(mock_question)
57 - assigns[:prompt].should equal(mock_prompt)  
58 - assigns[:a].should equal(mock_appearance) 61 + assigns[:p].should be_nil
  62 + assigns[:a].should be_nil
  63 + end
  64 +
  65 + describe "creates an appearance" do
  66 + before(:each) do
  67 + @visitor_identifier = "somelongunique32charstring"
  68 + #stub broken
  69 + visitor_list = [mock_visitor]
  70 + @user.stub!(:visitors).and_return(visitor_list)
  71 + visitor_list.stub!(:find_or_create_by_identifier).and_return(mock_visitor)
  72 + @user.stub!(:record_appearance).with(mock_visitor, mock_prompt).and_return(mock_appearance)
  73 + end
  74 +
  75 + #TODO this is not a particularly intutive param to pass in order to create an appearance
  76 + it "creates an appearance when a visitor identifier is a param" do
  77 + get :show, :id => "37", :visitor_identifier => @visitor_identifier
  78 + assigns[:question].should equal(mock_question)
  79 + assigns[:p].should equal(mock_prompt)
  80 + assigns[:a].should equal(mock_appearance)
  81 +
  82 + end
59 83
  84 + it "does not create an appearance when the 'barebones' param is set, even when a visitor id is sent" do
  85 + get :show, :id => "37", :barebones => true, :visitor_identifier => @visitor_identifier
  86 + assigns[:question].should equal(mock_question)
  87 + assigns[:p].should be_nil
  88 + assigns[:a].should be_nil
  89 + end
  90 +
  91 + describe "calls catchup algorithm" do
  92 + before(:each) do
  93 + mock_question.should_receive(:send_later).with(:add_prompt_to_queue)
  94 + end
  95 +
  96 +
  97 + #TODO Refactor out to use uses_catchup?
  98 + it "should pop prompt from cached queue using the catchup algorithm if params dictate" do
  99 + mock_question.should_receive(:pop_prompt_queue).and_return(mock_prompt)
  100 +
  101 + get :show, :id => "37", :visitor_identifier => @visitor_identifier, :algorithm => "catchup"
  102 + assigns[:question].should equal(mock_question)
  103 + assigns[:p].should equal(mock_prompt)
  104 + assigns[:a].should equal(mock_appearance)
  105 + end
  106 +
  107 + it "should handle cache misses gracefully" do
  108 + mock_question.should_receive(:pop_prompt_queue).and_return(nil)
  109 + mock_question.should_receive(:catchup_choose_prompt).and_return(mock_prompt)
  110 +
  111 + get :show, :id => "37", :visitor_identifier => @visitor_identifier, :algorithm => "catchup"
  112 + assigns[:question].should equal(mock_question)
  113 + assigns[:p].should equal(mock_prompt)
  114 + assigns[:a].should equal(mock_appearance)
  115 + end
  116 + end
60 end 117 end
61 end 118 end
  119 +
62 # 120 #
63 # describe "GET new" do 121 # describe "GET new" do
64 # it "assigns a new question as @question" do 122 # it "assigns a new question as @question" do
spec/models/user_spec.rb
@@ -11,7 +11,8 @@ describe User do @@ -11,7 +11,8 @@ describe User do
11 @rc = Factory.create(:choice, :question => @question, :creator => @johndoe, :data => 'goodbye gorgeous') 11 @rc = Factory.create(:choice, :question => @question, :creator => @johndoe, :data => 'goodbye gorgeous')
12 @prompt = Factory.create(:prompt, :question => @question, :tracking => 'sample', :left_choice => @lc, :right_choice => @rc) 12 @prompt = Factory.create(:prompt, :question => @question, :tracking => 'sample', :left_choice => @lc, :right_choice => @rc)
13 13
14 - @appearance = @aoi_clone.record_appearance("test visitor identifier", @prompt) 14 + @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier")
  15 + @appearance = @aoi_clone.record_appearance(@visitor, @prompt)
15 end 16 end
16 17
17 18
spec/models/visitor_spec.rb
@@ -15,7 +15,9 @@ describe Visitor do @@ -15,7 +15,9 @@ describe Visitor do
15 @lc = Factory.create(:choice, :question => @question, :creator => @johndoe, :data => 'hello gorgeous') 15 @lc = Factory.create(:choice, :question => @question, :creator => @johndoe, :data => 'hello gorgeous')
16 @rc = Factory.create(:choice, :question => @question, :creator => @johndoe, :data => 'goodbye gorgeous') 16 @rc = Factory.create(:choice, :question => @question, :creator => @johndoe, :data => 'goodbye gorgeous')
17 @prompt = Factory.create(:prompt, :question => @question, :tracking => 'sample', :left_choice => @lc, :right_choice => @rc) 17 @prompt = Factory.create(:prompt, :question => @question, :tracking => 'sample', :left_choice => @lc, :right_choice => @rc)
18 - @appearance = @aoi_clone.record_appearance("test visitor identifier", @prompt) 18 +
  19 + @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier")
  20 + @appearance = @aoi_clone.record_appearance(@visitor, @prompt)
19 @valid_attributes = { 21 @valid_attributes = {
20 :site => @aoi_clone, 22 :site => @aoi_clone,
21 :identifier => "value for identifier", 23 :identifier => "value for identifier",
spec/routing/clicks_routing_spec.rb
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')  
2 -  
3 -describe ClicksController do  
4 - #clicks is no longer accessible  
5 -end