Commit 11ba2339a44fae3247cb52a9f71180a335ca8f98
1 parent
3a6834a9
Exists in
master
and in
1 other branch
Refactoring promptscontroller#vote. Substantial test improvement
Showing
12 changed files
with
324 additions
and
133 deletions
Show diff stats
app/controllers/prompts_controller.rb
... | ... | @@ -5,7 +5,7 @@ class PromptsController < InheritedResources::Base |
5 | 5 | has_scope :active, :boolean => true, :only => :index |
6 | 6 | |
7 | 7 | has_scope :voted_on_by |
8 | - #before_filter :authenticate | |
8 | + before_filter :authenticate, :only => [:vote, :skip] | |
9 | 9 | |
10 | 10 | |
11 | 11 | def activate |
... | ... | @@ -23,64 +23,44 @@ class PromptsController < InheritedResources::Base |
23 | 23 | end |
24 | 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 | 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 | 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 | 64 | end |
85 | 65 | end |
86 | 66 | end |
... | ... | @@ -106,7 +86,6 @@ class PromptsController < InheritedResources::Base |
106 | 86 | |
107 | 87 | |
108 | 88 | def skip |
109 | - authenticate | |
110 | 89 | logger.info "#{current_user.inspect} is skipping." |
111 | 90 | @question = Question.find(params[:question_id]) |
112 | 91 | |
... | ... | @@ -124,7 +103,17 @@ class PromptsController < InheritedResources::Base |
124 | 103 | |
125 | 104 | |
126 | 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 | 118 | visitor = current_user.visitors.find_or_create_by_identifier(visitor_identifier) |
130 | 119 | @a = current_user.record_appearance(visitor, @next_prompt) | ... | ... |
app/models/choice.rb
... | ... | @@ -36,6 +36,12 @@ class Choice < ActiveRecord::Base |
36 | 36 | save! |
37 | 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 | 45 | def wins_plus_losses |
40 | 46 | #(prompts_on_the_left.collect(&:votes_count).sum + prompts_on_the_right.collect(&:votes_count).sum) |
41 | 47 | #Prompt.sum('votes_count', :conditions => "left_choice_id = #{id} OR right_choice_id = #{id}") |
... | ... | @@ -70,11 +76,6 @@ class Choice < ActiveRecord::Base |
70 | 76 | end |
71 | 77 | |
72 | 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 | 79 | (wins.to_f+1)/(wins+1+losses+1) * 100 |
79 | 80 | end |
80 | 81 | ... | ... |
app/models/user.rb
... | ... | @@ -31,12 +31,14 @@ class User < ActiveRecord::Base |
31 | 31 | return choice |
32 | 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 | 42 | end |
41 | 43 | |
42 | 44 | def record_appearance(visitor, prompt) | ... | ... |
app/models/visitor.rb
... | ... | @@ -16,26 +16,25 @@ class Visitor < ActiveRecord::Base |
16 | 16 | questions.include? question |
17 | 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 | 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 | 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 | 38 | end |
40 | 39 | |
41 | 40 | def skip!(appearance_lookup, prompt, time_viewed, options = {}) | ... | ... |
app/models/vote.rb
1 | 1 | class Vote < ActiveRecord::Base |
2 | 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 | 9 | belongs_to :voter, :class_name => "Visitor", :foreign_key => "voter_id" |
4 | 10 | belongs_to :question, :counter_cache => true |
5 | 11 | belongs_to :prompt, :counter_cache => true |
... | ... | @@ -11,4 +17,14 @@ class Vote < ActiveRecord::Base |
11 | 17 | named_scope :with_question, lambda { |*args| {:conditions => {:question_id => args.first }} } |
12 | 18 | named_scope :with_voter_ids, lambda { |*args| {:conditions => {:voter_id=> args.first }} } |
13 | 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 | 30 | end | ... | ... |
config/routes.rb
... | ... | @@ -13,7 +13,7 @@ ActionController::Routing::Routes.draw do |map| |
13 | 13 | :object_info_totals_by_question_id => :get, |
14 | 14 | :recent_votes_by_question_id => :get} do |question| |
15 | 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 | 17 | :collection => {:single => :get, :index => :get} |
18 | 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 | 19 | end | ... | ... |
spec/controllers/prompts_controller_spec.rb
... | ... | @@ -5,7 +5,7 @@ describe PromptsController do |
5 | 5 | @controller.current_user = user |
6 | 6 | return user |
7 | 7 | end |
8 | - # | |
8 | + | |
9 | 9 | before(:each) do |
10 | 10 | @question = Factory.create(:aoi_question) |
11 | 11 | sign_in_as(@aoi_clone = @question.site) |
... | ... | @@ -14,16 +14,6 @@ describe PromptsController do |
14 | 14 | @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier") |
15 | 15 | @appearance = @aoi_clone.record_appearance(@visitor, @prompt) |
16 | 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 | 18 | describe "GET show" do |
29 | 19 | it "assigns the requested prompt as @prompt" do |
... | ... | @@ -42,4 +32,39 @@ describe PromptsController do |
42 | 32 | end |
43 | 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 | 70 | end | ... | ... |
spec/controllers/questions_controller_spec.rb
... | ... | @@ -10,7 +10,6 @@ describe QuestionsController do |
10 | 10 | before(:each) do |
11 | 11 | @question = Factory.create(:aoi_question) |
12 | 12 | sign_in_as(@user = @question.site) |
13 | - @creator = @question.creator | |
14 | 13 | end |
15 | 14 | it "responds with basic question information" do |
16 | 15 | get :show, :id => @question.id, :format => "xml" | ... | ... |
spec/factories.rb
... | ... | @@ -39,6 +39,14 @@ Factory.define(:choice) do |f| |
39 | 39 | f.creator {|c| c.association(:visitor, :site => c.question.site)} |
40 | 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 | 50 | Factory.sequence :email do |n| |
43 | 51 | "user#{n}@example.com" |
44 | 52 | end | ... | ... |
spec/models/user_spec.rb
... | ... | @@ -29,18 +29,55 @@ describe User do |
29 | 29 | it "should be able to record a visitor's vote" do |
30 | 30 | @visitor = @aoi_clone.visitors.find_or_create_by_identifier("test_visitor_identifier") |
31 | 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 | 44 | prompt_votes = @prompt.votes(true) |
34 | 45 | prompt_votes.should_not be_empty |
35 | - prompt_votes.size.should eql 1 | |
46 | + prompt_votes.size.should == 1 | |
36 | 47 | |
37 | 48 | choices = @prompt.choices |
38 | - #@question.prompts(true).size.should == 2 | |
39 | 49 | choices.should_not be_empty |
40 | 50 | |
41 | 51 | choice_votes = choices[0].votes(true) |
42 | 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 | 81 | end |
45 | 82 | |
46 | 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 | 11 | before(:each) do |
12 | 12 | @question = Factory.create(:aoi_question) |
13 | 13 | @aoi_clone = @question.site |
14 | - @johndoe = @question.creator | |
15 | 14 | |
16 | 15 | @prompt = @question.prompts.first |
17 | - @lc = @prompt.left_choice | |
18 | - @rc = @prompt.right_choice | |
19 | - | |
20 | 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 | 20 | end |
28 | 21 | |
29 | 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 | 24 | end |
33 | 25 | |
34 | 26 | it "should be able to determine ownership of a question" do |
35 | 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 | 31 | ownedquestion = Factory.create(:question, :site => @aoi_clone, :creator=> @johndoe) |
38 | 32 | @johndoe.owns?(ownedquestion).should be_true |
39 | 33 | end |
40 | 34 | |
41 | 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 | 91 | end |
46 | 92 | |
47 | 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 | 96 | end |
52 | 97 | |
53 | 98 | it "should accurately update score counts after vote" do |
99 | + | |
100 | + @lc = @prompt.left_choice | |
101 | + @rc = @prompt.right_choice | |
102 | + | |
54 | 103 | prev_winner_score = @lc.score |
55 | 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 | 108 | @lc.reload |
60 | 109 | @rc.reload |
... | ... | @@ -64,12 +113,14 @@ describe Visitor do |
64 | 113 | end |
65 | 114 | |
66 | 115 | it "should accurately update win and loss totals after vote" do |
116 | + @lc = @prompt.left_choice | |
117 | + @rc = @prompt.right_choice | |
67 | 118 | prev_winner_wins = @lc.wins |
68 | 119 | prev_winner_losses = @lc.losses |
69 | 120 | prev_loser_losses = @rc.losses |
70 | 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 | 125 | @lc.reload |
75 | 126 | @rc.reload | ... | ... |
spec/models/vote_spec.rb
1 | 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') |
2 | 2 | |
3 | 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 | 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 | 82 | end |
19 | 83 | end | ... | ... |