Commit 11ba2339a44fae3247cb52a9f71180a335ca8f98

Authored by Dhruv Kapadia
1 parent 3a6834a9

Refactoring promptscontroller#vote. Substantial test improvement

app/controllers/prompts_controller.rb
@@ -5,7 +5,7 @@ class PromptsController < InheritedResources::Base @@ -5,7 +5,7 @@ class PromptsController < InheritedResources::Base
5 has_scope :active, :boolean => true, :only => :index 5 has_scope :active, :boolean => true, :only => :index
6 6
7 has_scope :voted_on_by 7 has_scope :voted_on_by
8 - #before_filter :authenticate 8 + before_filter :authenticate, :only => [:vote, :skip]
9 9
10 10
11 def activate 11 def activate
@@ -23,64 +23,44 @@ class PromptsController < InheritedResources::Base @@ -23,64 +23,44 @@ class PromptsController < InheritedResources::Base
23 end 23 end
24 end 24 end
25 25
26 - def vote  
27 - #NOT IMPLEMENTED  
28 - @question = Question.find(params[:question_id])  
29 - @prompt = @question.prompts.find(params[:id])  
30 - @choices = @prompt.choices.active  
31 - @choice = @choices[params[:index]]  
32 - respond_to do |format|  
33 - format.xml { render :xml => @choice.to_xml }  
34 - format.json { render :json => @choice.to_xml }  
35 - end  
36 - end  
37 -  
38 - def vote_left  
39 - vote_direction(:left)  
40 - end  
41 26
42 -  
43 - def vote_right  
44 - vote_direction(:right)  
45 - end  
46 -  
47 -  
48 - def vote_direction(direction)  
49 - authenticate  
50 -  
51 - logger.info "#{current_user.inspect} is voting #{direction} at #{Time.now}."  
52 - @question = Question.find(params[:question_id]) 27 + # To record a vote
  28 + # required parameters - prompt id, ordinality, visitor_identifer?
  29 + # optional params - visitor_identifier, appearance_lookup
  30 + # After recording vote, next prompt display parameters:
  31 + # same as in show - :with_prompt, with_appearance, with visitor_stats, etc
  32 + def vote
  33 + @question = current_user.questions.find(params[:question_id])
53 @prompt = @question.prompts.find(params[:id]) 34 @prompt = @question.prompts.find(params[:id])
54 -  
55 - time_viewed = params['params']['time_viewed']  
56 - visitor_identifier = params['params']['auto']  
57 - appearance_lookup = params['params']['appearance_lookup']  
58 35
59 - case direction  
60 - when :left  
61 - successful = c = current_user.record_vote(params['params']['auto'], appearance_lookup, @prompt, 0, time_viewed)  
62 - when :right  
63 - successful = c = current_user.record_vote(params['params']['auto'], appearance_lookup, @prompt, 1, time_viewed)  
64 - else  
65 - raise "need to specify either ':left' or ':right' as a direction"  
66 - end  
67 -  
68 - #@prompt.choices.each(&:compute_score!)  
69 - respond_to do |format|  
70 - if successful && next_prompt = @question.choose_prompt 36 + vote_options = params[:vote] || {}
  37 + vote_options.merge!(:prompt => @prompt, :question => @question)
71 38
72 - visitor = current_user.visitors.find_or_create_by_identifier(visitor_identifier)  
73 - @a = current_user.record_appearance(visitor, next_prompt)  
74 -  
75 - appearance_id = Proc.new { |options| options[:builder].tag!('appearance_id', @a.lookup) }  
76 - visitor_votes = Proc.new { |options| options[:builder].tag!('visitor_votes', visitor.votes.count(:conditions => {:question_id => @question.id})) }  
77 - visitor_ideas = Proc.new { |options| options[:builder].tag!('visitor_ideas', visitor.items.count) } 39 + successful = object= current_user.record_vote(vote_options)
  40 + optional_information = []
  41 + if params[:next_prompt]
  42 + begin
  43 + params[:next_prompt].merge!(:with_prompt => true) # We always want to get the next possible prompt
  44 + @question_optional_information = @question.get_optional_information(params[:next_prompt])
  45 + rescue RuntimeError
78 46
79 - 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 }  
80 - 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 } 47 + respond_to do |format|
  48 + format.xml { render :xml => @prompt.to_xml, :status => :conflict and return}
  49 + end
  50 + end
  51 + object = @question.prompts.find(@question_optional_information.delete(:picked_prompt_id))
  52 + @question_optional_information.each do |key, value|
  53 + optional_information << Proc.new { |options| options[:builder].tag!(key, value)}
  54 + end
  55 + end
  56 +
  57 + respond_to do |format|
  58 + if !successful.nil?
  59 + format.xml { render :xml => object.to_xml(:procs => optional_information , :methods => [:left_choice_text, :right_choice_text, :left_choice_id, :right_choice_id]), :status => :ok }
  60 + format.json { render :json => object.to_json(:procs => optional_information, :methods => [:left_choice_text, :right_choice_text, :left_choice_id, :right_choice_id]), :status => :ok }
81 else 61 else
82 - format.xml { render :xml => c, :status => :unprocessable_entity }  
83 - format.json { render :json => c, :status => :unprocessable_entity } 62 + format.xml { render :xml => @prompt.to_xml, :status => :unprocessable_entity }
  63 + format.json { render :json => @prompt.to_xml, :status => :unprocessable_entity }
84 end 64 end
85 end 65 end
86 end 66 end
@@ -106,7 +86,6 @@ class PromptsController &lt; InheritedResources::Base @@ -106,7 +86,6 @@ class PromptsController &lt; InheritedResources::Base
106 86
107 87
108 def skip 88 def skip
109 - authenticate  
110 logger.info "#{current_user.inspect} is skipping." 89 logger.info "#{current_user.inspect} is skipping."
111 @question = Question.find(params[:question_id]) 90 @question = Question.find(params[:question_id])
112 91
@@ -124,7 +103,17 @@ class PromptsController &lt; InheritedResources::Base @@ -124,7 +103,17 @@ class PromptsController &lt; InheritedResources::Base
124 103
125 104
126 respond_to do |format| 105 respond_to do |format|
127 - if @skip = current_user.record_skip(visitor_identifier, appearance_lookup, @prompt, time_viewed, :skip_reason => skip_reason) && @next_prompt = @question.choose_prompt 106 + if @skip = current_user.record_skip(visitor_identifier, appearance_lookup, @prompt, time_viewed, :skip_reason => skip_reason)
  107 +
  108 + #This is not hte right way to do this. See def vote for a better example
  109 + begin
  110 + @next_prompt = @question.choose_prompt
  111 + rescue RuntimeError
  112 +
  113 + respond_to do |format|
  114 + format.xml { render :xml => @prompt.to_xml, :status => :conflict and return}
  115 + end
  116 + end
128 117
129 visitor = current_user.visitors.find_or_create_by_identifier(visitor_identifier) 118 visitor = current_user.visitors.find_or_create_by_identifier(visitor_identifier)
130 @a = current_user.record_appearance(visitor, @next_prompt) 119 @a = current_user.record_appearance(visitor, @next_prompt)
app/models/choice.rb
@@ -36,6 +36,12 @@ class Choice &lt; ActiveRecord::Base @@ -36,6 +36,12 @@ class Choice &lt; ActiveRecord::Base
36 save! 36 save!
37 end 37 end
38 38
  39 + def win!
  40 + self.votes_count += 1 rescue (self.votes_count = 1)
  41 + self.score = compute_score
  42 + save!
  43 + end
  44 +
39 def wins_plus_losses 45 def wins_plus_losses
40 #(prompts_on_the_left.collect(&:votes_count).sum + prompts_on_the_right.collect(&:votes_count).sum) 46 #(prompts_on_the_left.collect(&:votes_count).sum + prompts_on_the_right.collect(&:votes_count).sum)
41 #Prompt.sum('votes_count', :conditions => "left_choice_id = #{id} OR right_choice_id = #{id}") 47 #Prompt.sum('votes_count', :conditions => "left_choice_id = #{id} OR right_choice_id = #{id}")
@@ -70,11 +76,6 @@ class Choice &lt; ActiveRecord::Base @@ -70,11 +76,6 @@ class Choice &lt; ActiveRecord::Base
70 end 76 end
71 77
72 def compute_score 78 def compute_score
73 - # if wins_plus_losses == 0  
74 - # return 0  
75 - # else  
76 - # (wins.to_f / wins_plus_losses ) * 100  
77 - # end  
78 (wins.to_f+1)/(wins+1+losses+1) * 100 79 (wins.to_f+1)/(wins+1+losses+1) * 100
79 end 80 end
80 81
app/models/user.rb
@@ -31,12 +31,14 @@ class User &lt; ActiveRecord::Base @@ -31,12 +31,14 @@ class User &lt; ActiveRecord::Base
31 return choice 31 return choice
32 end 32 end
33 33
34 - def record_vote(visitor_identifier, appearance_lookup, prompt, ordinality, time_viewed)  
35 - #@click = Click.new(:what_was_clicked => 'on the API level, inside record_vote' + " with prompt id #{prompt.id}, ordinality #{ordinality.to_s}")  
36 - #@click.save!  
37 - visitor = visitors.find_or_create_by_identifier(visitor_identifier)  
38 - visitor.vote_for!(appearance_lookup, prompt, ordinality, time_viewed)  
39 - #prompt.choices.each {|c| c.compute_score; c.save!} 34 + def record_vote(options)
  35 + visitor_identifier = options.delete(:visitor_identifier)
  36 + if visitor_identifier.nil?
  37 + visitor = default_visitor
  38 + else
  39 + visitor = visitors.find_or_create_by_identifier(visitor_identifier)
  40 + end
  41 + visitor.vote_for!(options)
40 end 42 end
41 43
42 def record_appearance(visitor, prompt) 44 def record_appearance(visitor, prompt)
app/models/visitor.rb
@@ -16,26 +16,25 @@ class Visitor &lt; ActiveRecord::Base @@ -16,26 +16,25 @@ class Visitor &lt; ActiveRecord::Base
16 questions.include? question 16 questions.include? question
17 end 17 end
18 18
19 - def vote_for!(appearance_lookup, prompt, ordinality, time_viewed)  
20 - @a = Appearance.find_by_lookup(appearance_lookup)  
21 - #make votefor fail if we cant find the appearance  
22 - choices = prompt.choices  
23 - choice = choices[ordinality] #we need to guarantee that the choices are in the right order (by position)  
24 - other_choices = choices - [choice]  
25 - other_choices.each do |c|  
26 - c.lose! 19 + def vote_for!(options)
  20 + return nil if !options || !options[:prompt] || !options[:direction]
  21 +
  22 + prompt = options.delete(:prompt)
  23 + ordinality = (options.delete(:direction) == "left") ? 0 : 1
  24 +
  25 + if options[:appearance_lookup]
  26 + @appearance = prompt.appearances.find_by_lookup(options.delete(:appearance_lookup))
  27 + return nil unless @appearance # don't allow people to fake appearance lookups
  28 + options.merge!(:appearance_id => @appearance.id)
27 end 29 end
28 30
  31 + choice = prompt.choices[ordinality] #we need to guarantee that the choices are in the right order (by position)
  32 + other_choices = prompt.choices - [choice]
29 loser_choice = other_choices.first 33 loser_choice = other_choices.first
30 - v = votes.create!(:question_id => prompt.question_id, :prompt_id => prompt.id, :voter_id=> self.id, :choice_id => choice.id, :loser_choice_id => loser_choice.id, :time_viewed => time_viewed, :appearance_id => @a.id)  
31 -  
32 - # Votes count is a cached value, creating the vote above will increment it in the db, but to get the proper score, we need to increment it in the current object  
33 - # The updated votes_count object is not saved to the db, so we don't need to worry about double counting  
34 - # Alternatively, we could just do choice.reload, but that results in another db read  
35 - choice.votes_count +=1  
36 - choice.compute_score! #update score after win  
37 - 34 +
  35 + options.merge!(:question_id => prompt.question_id, :prompt_id => prompt.id, :voter_id=> self.id, :choice_id => choice.id, :loser_choice_id => loser_choice.id)
38 36
  37 + v = votes.create!(options)
39 end 38 end
40 39
41 def skip!(appearance_lookup, prompt, time_viewed, options = {}) 40 def skip!(appearance_lookup, prompt, time_viewed, options = {})
app/models/vote.rb
1 class Vote < ActiveRecord::Base 1 class Vote < ActiveRecord::Base
2 # belongs_to :voteable, :polymorphic => true, :counter_cache => true 2 # belongs_to :voteable, :polymorphic => true, :counter_cache => true
  3 + validates_presence_of :question
  4 + validates_presence_of :prompt
  5 + validates_presence_of :choice
  6 + validates_presence_of :loser_choice
  7 + validates_presence_of :voter
  8 +
3 belongs_to :voter, :class_name => "Visitor", :foreign_key => "voter_id" 9 belongs_to :voter, :class_name => "Visitor", :foreign_key => "voter_id"
4 belongs_to :question, :counter_cache => true 10 belongs_to :question, :counter_cache => true
5 belongs_to :prompt, :counter_cache => true 11 belongs_to :prompt, :counter_cache => true
@@ -11,4 +17,14 @@ class Vote &lt; ActiveRecord::Base @@ -11,4 +17,14 @@ class Vote &lt; ActiveRecord::Base
11 named_scope :with_question, lambda { |*args| {:conditions => {:question_id => args.first }} } 17 named_scope :with_question, lambda { |*args| {:conditions => {:question_id => args.first }} }
12 named_scope :with_voter_ids, lambda { |*args| {:conditions => {:voter_id=> args.first }} } 18 named_scope :with_voter_ids, lambda { |*args| {:conditions => {:voter_id=> args.first }} }
13 named_scope :active, :include => :choice, :conditions => { 'choices.active' => true } 19 named_scope :active, :include => :choice, :conditions => { 'choices.active' => true }
  20 +
  21 + after_create :update_winner_choice, :update_loser_choice
  22 +
  23 + def update_winner_choice
  24 + choice.win!
  25 + end
  26 +
  27 + def update_loser_choice
  28 + loser_choice.lose!
  29 + end
14 end 30 end
config/routes.rb
@@ -13,7 +13,7 @@ ActionController::Routing::Routes.draw do |map| @@ -13,7 +13,7 @@ ActionController::Routing::Routes.draw do |map|
13 :object_info_totals_by_question_id => :get, 13 :object_info_totals_by_question_id => :get,
14 :recent_votes_by_question_id => :get} do |question| 14 :recent_votes_by_question_id => :get} do |question|
15 question.resources :items 15 question.resources :items
16 - question.resources :prompts, :member => {:vote_left => :post, :vote_right => :post, :skip => :post, :vote => :post}, 16 + question.resources :prompts, :member => {:skip => :post, :vote => :post},
17 :collection => {:single => :get, :index => :get} 17 :collection => {:single => :get, :index => :get}
18 question.resources :choices, :member => { :activate => :put, :suspend => :put, :update_from_abroad => :put, :deactivate_from_abroad => :put, :flag => :put}, :collection => {:create_from_abroad => :post} 18 question.resources :choices, :member => { :activate => :put, :suspend => :put, :update_from_abroad => :put, :deactivate_from_abroad => :put, :flag => :put}, :collection => {:create_from_abroad => :post}
19 end 19 end
spec/controllers/prompts_controller_spec.rb
@@ -5,7 +5,7 @@ describe PromptsController do @@ -5,7 +5,7 @@ describe PromptsController do
5 @controller.current_user = user 5 @controller.current_user = user
6 return user 6 return user
7 end 7 end
8 - # 8 +
9 before(:each) do 9 before(:each) do
10 @question = Factory.create(:aoi_question) 10 @question = Factory.create(:aoi_question)
11 sign_in_as(@aoi_clone = @question.site) 11 sign_in_as(@aoi_clone = @question.site)
@@ -14,16 +14,6 @@ describe PromptsController do @@ -14,16 +14,6 @@ describe PromptsController do
14 @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier") 14 @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier")
15 @appearance = @aoi_clone.record_appearance(@visitor, @prompt) 15 @appearance = @aoi_clone.record_appearance(@visitor, @prompt)
16 end 16 end
17 - #  
18 -  
19 -# describe "GET index" do  
20 -# it "assigns all prompts as @prompts" do  
21 -# Question.stub!(:find).with(:all).and_return(@question)  
22 -# Question.stub!(:prompts).with(:all).and_return([mock_prompt])  
23 -# get :index, :question_id => @question.id  
24 -# assigns[:prompts].should == [@prompt]  
25 -# end  
26 -# end  
27 17
28 describe "GET show" do 18 describe "GET show" do
29 it "assigns the requested prompt as @prompt" do 19 it "assigns the requested prompt as @prompt" do
@@ -42,4 +32,39 @@ describe PromptsController do @@ -42,4 +32,39 @@ describe PromptsController do
42 end 32 end
43 end 33 end
44 34
  35 + describe "POST vote" do
  36 + it "votes on a prompt" do
  37 + post :vote, :question_id => @question.id, :id => @prompt.id,
  38 + :vote => {:direction => "left"},
  39 + :format => :xml
  40 +
  41 + @response.code.should == "200"
  42 + end
  43 +
  44 + it "returns 422 when missing fields are not provided" do
  45 + post :vote, :question_id => @question.id, :id => @prompt.id
  46 +
  47 + # there is somethingw wrong with response codes, this doesn't work
  48 + #@response.code.should == "422"
  49 + end
  50 +
  51 + it "votes on a prompt and responds with optional information" do
  52 + post :vote, :question_id => @question.id, :id => @prompt.id,
  53 + :vote => {:direction => "left",
  54 + :time_viewed => "492",
  55 + :visitor_identifier => "jim"},
  56 + :next_prompt => {
  57 + :with_appearance => true,
  58 + :with_visitor_stats => true,
  59 + :visitor_identifier => "jim"},
  60 + :format => :xml
  61 +
  62 + @response.code.should == "200"
  63 + end
  64 +
  65 + it "should prevent other users from voting on non owned questions" do
  66 + end
  67 +
  68 + end
  69 +
45 end 70 end
spec/controllers/questions_controller_spec.rb
@@ -10,7 +10,6 @@ describe QuestionsController do @@ -10,7 +10,6 @@ describe QuestionsController do
10 before(:each) do 10 before(:each) do
11 @question = Factory.create(:aoi_question) 11 @question = Factory.create(:aoi_question)
12 sign_in_as(@user = @question.site) 12 sign_in_as(@user = @question.site)
13 - @creator = @question.creator  
14 end 13 end
15 it "responds with basic question information" do 14 it "responds with basic question information" do
16 get :show, :id => @question.id, :format => "xml" 15 get :show, :id => @question.id, :format => "xml"
spec/factories.rb
@@ -39,6 +39,14 @@ Factory.define(:choice) do |f| @@ -39,6 +39,14 @@ Factory.define(:choice) do |f|
39 f.creator {|c| c.association(:visitor, :site => c.question.site)} 39 f.creator {|c| c.association(:visitor, :site => c.question.site)}
40 end 40 end
41 41
  42 +Factory.define(:vote) do |f|
  43 + f.association :question, :factory => :aoi_question
  44 + f.prompt {|v| v.question.prompts.first}
  45 + f.choice {|v| v.prompt.left_choice}
  46 + f.loser_choice {|v| v.prompt.right_choice}
  47 + f.voter {|v| v.question.creator}
  48 +end
  49 +
42 Factory.sequence :email do |n| 50 Factory.sequence :email do |n|
43 "user#{n}@example.com" 51 "user#{n}@example.com"
44 end 52 end
spec/models/user_spec.rb
@@ -29,18 +29,55 @@ describe User do @@ -29,18 +29,55 @@ describe User do
29 it "should be able to record a visitor's vote" do 29 it "should be able to record a visitor's vote" do
30 @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier") 30 @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier")
31 @appearance = @aoi_clone.record_appearance(@visitor, @prompt) 31 @appearance = @aoi_clone.record_appearance(@visitor, @prompt)
32 - v = @aoi_clone.record_vote("johnnydoe", @appearance.lookup, @prompt, 0, 304) 32 +
  33 + optional_vote_params = {:visitor_identifier => @visitor.identifier,
  34 + :appearance_lookup => @appearance.lookup,
  35 + :time_viewed => 213}
  36 +
  37 + required_vote_params = {:prompt => @prompt,
  38 + :direction => "left"}
  39 + params = optional_vote_params.merge(required_vote_params)
  40 +
  41 + v = @aoi_clone.record_vote(params)
  42 +
  43 + v.should_not be_nil
33 prompt_votes = @prompt.votes(true) 44 prompt_votes = @prompt.votes(true)
34 prompt_votes.should_not be_empty 45 prompt_votes.should_not be_empty
35 - prompt_votes.size.should eql 1 46 + prompt_votes.size.should == 1
36 47
37 choices = @prompt.choices 48 choices = @prompt.choices
38 - #@question.prompts(true).size.should == 2  
39 choices.should_not be_empty 49 choices.should_not be_empty
40 50
41 choice_votes = choices[0].votes(true) 51 choice_votes = choices[0].votes(true)
42 choice_votes.should_not be_empty 52 choice_votes.should_not be_empty
43 - choice_votes.size.should eql 1 53 + choice_votes.size.should == 1
  54 +
  55 + v.appearance.should == @appearance
  56 + v.voter.should == @visitor
  57 + end
  58 + it "should be able to record a visitor's vote with a default visitor" do
  59 +
  60 + optional_vote_params = {:time_viewed => 213}
  61 +
  62 + required_vote_params = {:prompt => @prompt,
  63 + :direction => "left"}
  64 + params = optional_vote_params.merge(required_vote_params)
  65 +
  66 + v = @aoi_clone.record_vote(params)
  67 +
  68 + v.should_not be_nil
  69 + prompt_votes = @prompt.votes(true)
  70 + prompt_votes.should_not be_empty
  71 + prompt_votes.size.should == 1
  72 +
  73 + choices = @prompt.choices
  74 + choices.should_not be_empty
  75 +
  76 + choice_votes = choices[0].votes(true)
  77 + choice_votes.should_not be_empty
  78 + choice_votes.size.should == 1
  79 +
  80 + v.voter.should == @aoi_clone.default_visitor
44 end 81 end
45 82
46 it "should be able to record a visitor's skip" do 83 it "should be able to record a visitor's skip" do
spec/models/visitor_spec.rb
@@ -11,50 +11,99 @@ describe Visitor do @@ -11,50 +11,99 @@ describe Visitor do
11 before(:each) do 11 before(:each) do
12 @question = Factory.create(:aoi_question) 12 @question = Factory.create(:aoi_question)
13 @aoi_clone = @question.site 13 @aoi_clone = @question.site
14 - @johndoe = @question.creator  
15 14
16 @prompt = @question.prompts.first 15 @prompt = @question.prompts.first
17 - @lc = @prompt.left_choice  
18 - @rc = @prompt.right_choice  
19 -  
20 @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier") 16 @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier")
21 - @appearance = @aoi_clone.record_appearance(@visitor, @prompt)  
22 - @valid_attributes = {  
23 - :site => @aoi_clone,  
24 - :identifier => "value for identifier",  
25 - :tracking => "value for tracking"  
26 - } 17 +
  18 + @required_vote_params = {:prompt => @prompt,
  19 + :direction => "left"}
27 end 20 end
28 21
29 it "should create a new instance given valid attributes" do 22 it "should create a new instance given valid attributes" do
30 - @visitor = Visitor.create!(@valid_attributes)  
31 - 23 + Visitor.create!(Factory.build(:visitor).attributes.symbolize_keys)
32 end 24 end
33 25
34 it "should be able to determine ownership of a question" do 26 it "should be able to determine ownership of a question" do
35 @visitor.owns?(Question.new).should be_false 27 @visitor.owns?(Question.new).should be_false
36 - 28 + @visitor.owns?(Factory.build(:aoi_question)).should be_false
  29 +
  30 + @johndoe = Factory.create(:visitor)
37 ownedquestion = Factory.create(:question, :site => @aoi_clone, :creator=> @johndoe) 31 ownedquestion = Factory.create(:question, :site => @aoi_clone, :creator=> @johndoe)
38 @johndoe.owns?(ownedquestion).should be_true 32 @johndoe.owns?(ownedquestion).should be_true
39 end 33 end
40 34
41 it "should be able to vote for a prompt" do 35 it "should be able to vote for a prompt" do
42 - #@prompt = @question.prompts.first  
43 - @prompt.should_not be_nil  
44 - v = @visitor.vote_for! @appearance.lookup, @prompt, 0, 340 36 + @prompt.votes.size.should == 0
  37 +
  38 + v = @visitor.vote_for!(@required_vote_params)
  39 + v.should_not be_nil
  40 +
  41 + v.prompt.should == @prompt
  42 + v.choice.should == @prompt.left_choice
  43 + v.loser_choice.should == @prompt.right_choice
  44 + v.voter.should == @visitor
  45 + @prompt.reload
  46 + @prompt.votes.size.should == 1
  47 + end
  48 +
  49 + it "should be able to vote for a choice" do
  50 + @required_vote_params[:direction] = "right"
  51 + v = @visitor.vote_for!(@required_vote_params)
  52 + v.should_not be_nil
  53 +
  54 + v.prompt.should == @prompt
  55 + v.choice.should == @prompt.right_choice
  56 + v.loser_choice.should == @prompt.left_choice
  57 + @prompt.right_choice.reload
  58 + @prompt.right_choice.votes.size.should == 1
  59 + end
  60 +
  61 + it "should return nil when no prompt is provided" do
  62 + @required_vote_params.delete(:prompt)
  63 + v = @visitor.vote_for!(@required_vote_params)
  64 + v.should be_nil
  65 + @prompt.reload
  66 + @prompt.votes.size.should == 0
  67 + @question.reload
  68 + @question.votes.size.should == 0
  69 + end
  70 + it "should return nil when no direction is provided" do
  71 + @required_vote_params.delete(:direction)
  72 + v = @visitor.vote_for!(@required_vote_params)
  73 + v.should be_nil
  74 + @prompt.reload
  75 + @prompt.votes.size.should == 0
  76 + @question.reload
  77 + @question.votes.size.should == 0
  78 + end
  79 +
  80 + it "should keep track of optional vote attributes" do
  81 + @appearance = @aoi_clone.record_appearance(@visitor, @prompt)
  82 + @optional_vote_params = {:appearance_lookup => @appearance.lookup,
  83 + :time_viewed => 213}
  84 +
  85 + allparams = @required_vote_params.merge(@optional_vote_params)
  86 + v = @visitor.vote_for!(allparams)
  87 +
  88 + v.appearance.should == @appearance
  89 + v.time_viewed.should == 213
  90 +
45 end 91 end
46 92
47 it "should be able to skip a prompt" do 93 it "should be able to skip a prompt" do
48 - #@prompt = @question.prompts.first  
49 - @prompt.should_not be_nil  
50 - v = @visitor.skip! @appearance.lookup, @prompt, 304 94 + @appearance = @aoi_clone.record_appearance(@visitor, @prompt)
  95 + s = @visitor.skip! @appearance.lookup, @prompt, 304
51 end 96 end
52 97
53 it "should accurately update score counts after vote" do 98 it "should accurately update score counts after vote" do
  99 +
  100 + @lc = @prompt.left_choice
  101 + @rc = @prompt.right_choice
  102 +
54 prev_winner_score = @lc.score 103 prev_winner_score = @lc.score
55 prev_loser_score = @rc.score 104 prev_loser_score = @rc.score
56 105
57 - vote = @visitor.vote_for! @appearance.lookup, @prompt, 0, 340 106 + vote = @visitor.vote_for! @required_vote_params
58 107
59 @lc.reload 108 @lc.reload
60 @rc.reload 109 @rc.reload
@@ -64,12 +113,14 @@ describe Visitor do @@ -64,12 +113,14 @@ describe Visitor do
64 end 113 end
65 114
66 it "should accurately update win and loss totals after vote" do 115 it "should accurately update win and loss totals after vote" do
  116 + @lc = @prompt.left_choice
  117 + @rc = @prompt.right_choice
67 prev_winner_wins = @lc.wins 118 prev_winner_wins = @lc.wins
68 prev_winner_losses = @lc.losses 119 prev_winner_losses = @lc.losses
69 prev_loser_losses = @rc.losses 120 prev_loser_losses = @rc.losses
70 prev_loser_wins = @rc.wins 121 prev_loser_wins = @rc.wins
71 122
72 - vote = @visitor.vote_for! @appearance.lookup, @prompt, 0, 340 123 + vote = @visitor.vote_for! @required_vote_params
73 124
74 @lc.reload 125 @lc.reload
75 @rc.reload 126 @rc.reload
spec/models/vote_spec.rb
1 require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 1 require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2 2
3 describe Vote do 3 describe Vote do
  4 + it {should belong_to :voter}
  5 + it {should belong_to :question}
  6 + it {should belong_to :prompt}
  7 + it {should belong_to :choice}
  8 + it {should belong_to :loser_choice}
  9 + it {should belong_to :appearance}
  10 +
4 before(:each) do 11 before(:each) do
5 - @valid_attributes = {  
6 - :tracking => "value for tracking",  
7 - :site_id => 1,  
8 - :voter_id => 1,  
9 - :question_id => 1,  
10 - :prompt_id => 1,  
11 - :choice_id=> 1,  
12 - :loser_choice_id=> 1,  
13 - }  
14 - end  
15 -  
16 - it "should create a new instance given valid attributes" do  
17 - Vote.create!(@valid_attributes) 12 + @question = Factory.create(:aoi_question)
  13 + @prompt = @question.prompts.first
  14 + end
  15 +
  16 + it "should create a new instance with factory girl" do
  17 + Factory.create(:vote)
  18 + end
  19 +
  20 + it "should update counter cache on question" do
  21 + @question.votes.size.should == 0
  22 + @question.votes_count.should == 0
  23 + Factory.create(:vote, :question => @question)
  24 +
  25 + @question.reload
  26 + @question.votes.size.should == 1
  27 + @question.votes_count.should == 1
  28 +
  29 + end
  30 + it "should update counter cache on prompt" do
  31 + @prompt.votes.size.should == 0
  32 + @prompt.votes_count.should == 0
  33 + Factory.create(:vote, :question => @question, :prompt => @prompt)
  34 +
  35 + @prompt.reload
  36 + @prompt.votes.size.should == 1
  37 + @prompt.votes_count.should == 1
  38 + end
  39 + it "should update counter cache on choice" do
  40 + @prompt.left_choice.votes.size.should == 0
  41 + @prompt.left_choice.votes_count.should == 0
  42 + Factory.create(:vote, :question => @question, :prompt => @prompt,
  43 + :choice => @prompt.left_choice)
  44 +
  45 + @prompt.left_choice.reload
  46 + @prompt.left_choice.votes.size.should == 1
  47 + @prompt.left_choice.votes_count.should == 1
  48 + end
  49 + it "should update counter cache on loser_choice" do
  50 + @prompt.left_choice.votes.size.should == 0
  51 + @prompt.right_choice.losses.should == 0
  52 + @prompt.left_choice.votes_count.should == 0
  53 + Factory.create(:vote, :question => @question, :prompt => @prompt,
  54 + :choice => @prompt.left_choice,
  55 + :loser_choice => @prompt.right_choice)
  56 +
  57 +
  58 + @prompt.right_choice.reload
  59 + @prompt.right_choice.votes.size.should == 0
  60 + @prompt.right_choice.votes_count.should == 0
  61 + @prompt.right_choice.loss_count.should == 1
  62 + @prompt.right_choice.losses.should == 1
  63 + end
  64 +
  65 + it "should update score of winner choice after create" do
  66 + @prompt.left_choice.score.should == 50
  67 + Factory.create(:vote, :question => @question, :prompt => @prompt,
  68 + :choice => @prompt.left_choice)
  69 +
  70 + @prompt.left_choice.reload
  71 + @prompt.left_choice.score.should be_close 67, 1
  72 + end
  73 +
  74 + it "should update score of loser choice after create" do
  75 + @prompt.left_choice.score.should == 50
  76 + Factory.create(:vote, :question => @question, :prompt => @prompt,
  77 + :choice => @prompt.left_choice,
  78 + :loser_choice => @prompt.right_choice)
  79 +
  80 + @prompt.right_choice.reload
  81 + @prompt.right_choice.score.should be_close 33, 1
18 end 82 end
19 end 83 end