Commit c01226e12542a8656e25d9e19a53615a9c7e58ef
1 parent
3537faab
Exists in
master
and in
1 other branch
Appearance model added, tracks when prompts have been shown
Showing
9 changed files
with
94 additions
and
9 deletions
Show diff stats
app/controllers/prompts_controller.rb
| @@ -53,12 +53,16 @@ class PromptsController < InheritedResources::Base | @@ -53,12 +53,16 @@ class PromptsController < InheritedResources::Base | ||
| 53 | @prompt = @question.prompts.find(params[:id]) | 53 | @prompt = @question.prompts.find(params[:id]) |
| 54 | 54 | ||
| 55 | time_viewed = params['params']['time_viewed'] | 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 | case direction | 61 | case direction |
| 58 | when :left | 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 | when :right | 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 | else | 66 | else |
| 63 | raise "need to specify either ':left' or ':right' as a direction" | 67 | raise "need to specify either ':left' or ':right' as a direction" |
| 64 | end | 68 | end |
| @@ -74,8 +78,13 @@ class PromptsController < InheritedResources::Base | @@ -74,8 +78,13 @@ class PromptsController < InheritedResources::Base | ||
| 74 | next_prompt = @question.picked_prompt | 78 | next_prompt = @question.picked_prompt |
| 75 | end | 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 | else | 88 | else |
| 80 | format.xml { render :xml => c, :status => :unprocessable_entity } | 89 | format.xml { render :xml => c, :status => :unprocessable_entity } |
| 81 | format.json { render :json => c, :status => :unprocessable_entity } | 90 | format.json { render :json => c, :status => :unprocessable_entity } |
app/controllers/questions_controller.rb
| @@ -55,6 +55,7 @@ class QuestionsController < InheritedResources::Base | @@ -55,6 +55,7 @@ class QuestionsController < InheritedResources::Base | ||
| 55 | 55 | ||
| 56 | def show | 56 | def show |
| 57 | @question = Question.find(params[:id]) | 57 | @question = Question.find(params[:id]) |
| 58 | + visitor_identifier = params[:visitor_identifier] | ||
| 58 | unless params[:barebones] | 59 | unless params[:barebones] |
| 59 | if params[:algorithm] && params[:algorithm] == "catchup" | 60 | if params[:algorithm] && params[:algorithm] == "catchup" |
| 60 | logger.info("Question #{@question.id} requested catchup algorithm!") | 61 | logger.info("Question #{@question.id} requested catchup algorithm!") |
| @@ -62,13 +63,30 @@ class QuestionsController < InheritedResources::Base | @@ -62,13 +63,30 @@ class QuestionsController < InheritedResources::Base | ||
| 62 | else | 63 | else |
| 63 | @p = @question.picked_prompt | 64 | @p = @question.picked_prompt |
| 64 | end | 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 | left_choice_text = Proc.new { |options| options[:builder].tag!('left_choice_text', @p.left_choice.item.data) } | 75 | left_choice_text = Proc.new { |options| options[:builder].tag!('left_choice_text', @p.left_choice.item.data) } |
| 66 | right_choice_text = Proc.new { |options| options[:builder].tag!('right_choice_text', @p.right_choice.item.data) } | 76 | right_choice_text = Proc.new { |options| options[:builder].tag!('right_choice_text', @p.right_choice.item.data) } |
| 67 | picked_prompt_id = Proc.new { |options| options[:builder].tag!('picked_prompt_id', @p.id) } | 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 | show! do |format| | 86 | show! do |format| |
| 69 | session['prompts_ids'] ||= [] | 87 | session['prompts_ids'] ||= [] |
| 70 | format.xml { | 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 | end | 91 | end |
| 74 | else | 92 | else |
app/models/user.rb
| @@ -31,13 +31,21 @@ class User < ActiveRecord::Base | @@ -31,13 +31,21 @@ class User < ActiveRecord::Base | ||
| 31 | return choice | 31 | return choice |
| 32 | end | 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 | #@click = Click.new(:what_was_clicked => 'on the API level, inside record_vote' + " with prompt id #{prompt.id}, ordinality #{ordinality.to_s}") | 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! | 36 | #@click.save! |
| 37 | visitor = visitors.find_or_create_by_identifier(visitor_identifier) | 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 | #prompt.choices.each {|c| c.compute_score; c.save!} | 39 | #prompt.choices.each {|c| c.compute_score; c.save!} |
| 40 | end | 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 | def record_skip(visitor_identifier, prompt) | 50 | def record_skip(visitor_identifier, prompt) |
| 43 | visitor = visitors.find_or_create_by_identifier(visitor_identifier) | 51 | visitor = visitors.find_or_create_by_identifier(visitor_identifier) |
app/models/visitor.rb
| @@ -15,7 +15,8 @@ class Visitor < ActiveRecord::Base | @@ -15,7 +15,8 @@ class Visitor < ActiveRecord::Base | ||
| 15 | questions.include? question | 15 | questions.include? question |
| 16 | end | 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 | choices = prompt.choices | 20 | choices = prompt.choices |
| 20 | choice = choices[ordinality] #we need to guarantee that the choices are in the right order (by position) | 21 | choice = choices[ordinality] #we need to guarantee that the choices are in the right order (by position) |
| 21 | other_choices = choices - [choice] | 22 | other_choices = choices - [choice] |
| @@ -24,12 +25,15 @@ class Visitor < ActiveRecord::Base | @@ -24,12 +25,15 @@ class Visitor < ActiveRecord::Base | ||
| 24 | end | 25 | end |
| 25 | 26 | ||
| 26 | loser_choice = other_choices.first | 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 | # 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 | 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 | # The updated votes_count object is not saved to the db, so we don't need to worry about double counting | 31 | # The updated votes_count object is not saved to the db, so we don't need to worry about double counting |
| 30 | # Alternatively, we could just do choice.reload, but that results in another db read | 32 | # Alternatively, we could just do choice.reload, but that results in another db read |
| 31 | choice.votes_count +=1 | 33 | choice.votes_count +=1 |
| 32 | choice.compute_score! #update score after win | 34 | choice.compute_score! #update score after win |
| 35 | + | ||
| 36 | + | ||
| 33 | end | 37 | end |
| 34 | 38 | ||
| 35 | def skip!(prompt) | 39 | def skip!(prompt) |
app/models/vote.rb
| @@ -5,6 +5,7 @@ class Vote < ActiveRecord::Base | @@ -5,6 +5,7 @@ class Vote < ActiveRecord::Base | ||
| 5 | belongs_to :prompt, :counter_cache => true | 5 | belongs_to :prompt, :counter_cache => true |
| 6 | belongs_to :choice, :counter_cache => true | 6 | belongs_to :choice, :counter_cache => true |
| 7 | belongs_to :loser_choice, :class_name => "Choice", :foreign_key => "loser_choice_id" | 7 | belongs_to :loser_choice, :class_name => "Choice", :foreign_key => "loser_choice_id" |
| 8 | + belongs_to :appearance | ||
| 8 | 9 | ||
| 9 | named_scope :recent, lambda { |*args| {:conditions => ["created_at > ?", (args.first || Date.today.beginning_of_day)]} } | 10 | named_scope :recent, lambda { |*args| {:conditions => ["created_at > ?", (args.first || Date.today.beginning_of_day)]} } |
| 10 | named_scope :with_question, lambda { |*args| {:conditions => {:question_id => args.first }} } | 11 | named_scope :with_question, lambda { |*args| {:conditions => {:question_id => args.first }} } |
| @@ -0,0 +1,21 @@ | @@ -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 |
| @@ -0,0 +1,17 @@ | @@ -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 |