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 |