Commit c01226e12542a8656e25d9e19a53615a9c7e58ef

Authored by Dhruv Kapadia
1 parent 3537faab

Appearance model added, tracks when prompts have been shown

app/controllers/prompts_controller.rb
... ... @@ -53,12 +53,16 @@ class PromptsController < InheritedResources::Base
53 53 @prompt = @question.prompts.find(params[:id])
54 54  
55 55 time_viewed = params['params']['time_viewed']
  56 +
  57 + visitor_identifier = params['params']['auto']
  58 +
  59 + appearance_lookup = params['params']['appearance_lookup']
56 60  
57 61 case direction
58 62 when :left
59   - successful = c = current_user.record_vote(params['params']['auto'], @prompt, 0, time_viewed)
  63 + successful = c = current_user.record_vote(params['params']['auto'], appearance_lookup, @prompt, 0, time_viewed)
60 64 when :right
61   - successful = c = current_user.record_vote(params['params']['auto'], @prompt, 1, time_viewed)
  65 + successful = c = current_user.record_vote(params['params']['auto'], appearance_lookup, @prompt, 1, time_viewed)
62 66 else
63 67 raise "need to specify either ':left' or ':right' as a direction"
64 68 end
... ... @@ -74,8 +78,13 @@ class PromptsController < InheritedResources::Base
74 78 next_prompt = @question.picked_prompt
75 79 end
76 80  
77   - format.xml { render :xml => next_prompt.to_xml(:methods => [:left_choice_text, :right_choice_text, :left_choice_id, :right_choice_id]), :status => :ok }
78   - format.json { render :json => next_prompt.to_json(:methods => [:left_choice_text, :right_choice_text, :left_choice_id, :right_choice_id]), :status => :ok }
  81 +
  82 + @a = current_user.record_appearance(visitor_identifier, next_prompt)
  83 +
  84 + appearance_id = Proc.new { |options| options[:builder].tag!('appearance_id', @a.lookup) }
  85 +
  86 + 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 }
  87 + 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 }
79 88 else
80 89 format.xml { render :xml => c, :status => :unprocessable_entity }
81 90 format.json { render :json => c, :status => :unprocessable_entity }
... ...
app/controllers/questions_controller.rb
... ... @@ -55,6 +55,7 @@ class QuestionsController < InheritedResources::Base
55 55  
56 56 def show
57 57 @question = Question.find(params[:id])
  58 + visitor_identifier = params[:visitor_identifier]
58 59 unless params[:barebones]
59 60 if params[:algorithm] && params[:algorithm] == "catchup"
60 61 logger.info("Question #{@question.id} requested catchup algorithm!")
... ... @@ -62,13 +63,30 @@ class QuestionsController < InheritedResources::Base
62 63 else
63 64 @p = @question.picked_prompt
64 65 end
  66 +
  67 + # we sometimes request a question when no prompt is displayed
  68 + # TODO It would be a good idea to find these places and treat them like barebones
  69 + if visitor_identifier != ""
  70 + @a = current_user.record_appearance(visitor_identifier, @p)
  71 + else
  72 + @a = nil
  73 + end
  74 +
65 75 left_choice_text = Proc.new { |options| options[:builder].tag!('left_choice_text', @p.left_choice.item.data) }
66 76 right_choice_text = Proc.new { |options| options[:builder].tag!('right_choice_text', @p.right_choice.item.data) }
67 77 picked_prompt_id = Proc.new { |options| options[:builder].tag!('picked_prompt_id', @p.id) }
  78 + appearance_id = Proc.new { |options| options[:builder].tag!('appearance_id', @a.lookup) }
  79 +
  80 + the_procs = [left_choice_text, right_choice_text, picked_prompt_id]
  81 +
  82 + if @a
  83 + the_procs << appearance_id
  84 + end
  85 +
68 86 show! do |format|
69 87 session['prompts_ids'] ||= []
70 88 format.xml {
71   - render :xml => @question.to_xml(:methods => [:item_count], :procs => [left_choice_text, right_choice_text, picked_prompt_id])
  89 + render :xml => @question.to_xml(:methods => [:item_count], :procs => the_procs)
72 90 }
73 91 end
74 92 else
... ...
app/models/appearance.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +class Appearance < ActiveRecord::Base
  2 + belongs_to :voter, :class_name => "Visitor", :foreign_key => 'voter_id'
  3 + belongs_to :prompt
  4 + belongs_to :question
  5 + has_one :vote
  6 +
  7 +end
... ...
app/models/user.rb
... ... @@ -31,13 +31,21 @@ class User &lt; ActiveRecord::Base
31 31 return choice
32 32 end
33 33  
34   - def record_vote(visitor_identifier, prompt, ordinality, time_viewed)
  34 + def record_vote(visitor_identifier, appearance_lookup, prompt, ordinality, time_viewed)
35 35 #@click = Click.new(:what_was_clicked => 'on the API level, inside record_vote' + " with prompt id #{prompt.id}, ordinality #{ordinality.to_s}")
36 36 #@click.save!
37 37 visitor = visitors.find_or_create_by_identifier(visitor_identifier)
38   - visitor.vote_for!(prompt, ordinality, time_viewed)
  38 + visitor.vote_for!(appearance_lookup, prompt, ordinality, time_viewed)
39 39 #prompt.choices.each {|c| c.compute_score; c.save!}
40 40 end
  41 +
  42 + def record_appearance(visitor_identifier, prompt)
  43 + visitor = visitors.find_or_create_by_identifier(visitor_identifier)
  44 +
  45 + 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) )
  47 + end
  48 +
41 49  
42 50 def record_skip(visitor_identifier, prompt)
43 51 visitor = visitors.find_or_create_by_identifier(visitor_identifier)
... ...
app/models/visitor.rb
... ... @@ -15,7 +15,8 @@ class Visitor &lt; ActiveRecord::Base
15 15 questions.include? question
16 16 end
17 17  
18   - def vote_for!(prompt, ordinality, time_viewed)
  18 + def vote_for!(appearance_lookup, prompt, ordinality, time_viewed)
  19 + @a = Appearance.find_by_lookup(appearance_lookup)
19 20 choices = prompt.choices
20 21 choice = choices[ordinality] #we need to guarantee that the choices are in the right order (by position)
21 22 other_choices = choices - [choice]
... ... @@ -24,12 +25,15 @@ class Visitor &lt; ActiveRecord::Base
24 25 end
25 26  
26 27 loser_choice = other_choices.first
27   - 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)
  28 + 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)
  29 +
28 30 # 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
29 31 # The updated votes_count object is not saved to the db, so we don't need to worry about double counting
30 32 # Alternatively, we could just do choice.reload, but that results in another db read
31 33 choice.votes_count +=1
32 34 choice.compute_score! #update score after win
  35 +
  36 +
33 37 end
34 38  
35 39 def skip!(prompt)
... ...
app/models/vote.rb
... ... @@ -5,6 +5,7 @@ class Vote &lt; ActiveRecord::Base
5 5 belongs_to :prompt, :counter_cache => true
6 6 belongs_to :choice, :counter_cache => true
7 7 belongs_to :loser_choice, :class_name => "Choice", :foreign_key => "loser_choice_id"
  8 + belongs_to :appearance
8 9  
9 10 named_scope :recent, lambda { |*args| {:conditions => ["created_at > ?", (args.first || Date.today.beginning_of_day)]} }
10 11 named_scope :with_question, lambda { |*args| {:conditions => {:question_id => args.first }} }
... ...
db/migrate/20100401230916_create_appearances.rb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +class CreateAppearances < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :appearances do |table|
  4 + table.integer :voter_id
  5 + table.integer :site_id
  6 + table.integer :prompt_id
  7 + table.integer :question_id
  8 + table.string :lookup
  9 + table.timestamps
  10 + end
  11 +
  12 + add_column :votes, :appearance_id, :integer
  13 + add_index :appearances, :lookup
  14 +
  15 + end
  16 +
  17 + def self.down
  18 + drop_table :appearances
  19 + remove_column :votes, :appearance_id, :integer
  20 + end
  21 +end
... ...
spec/fixtures/appearances.yml 0 → 100644
spec/models/appearance_spec.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +require 'spec_helper'
  2 +
  3 +describe Appearance do
  4 + before(:each) do
  5 + @valid_attributes = {
  6 + :voter_id => ,
  7 + :site_id => ,
  8 + :prompt_id => ,
  9 + :question_id => ,
  10 + :vote_id => 1
  11 + }
  12 + end
  13 +
  14 + it "should create a new instance given valid attributes" do
  15 + Appearance.create!(@valid_attributes)
  16 + end
  17 +end
... ...