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 | 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/user.rb
... | ... | @@ -31,13 +31,21 @@ class User < 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 < 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 < 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 < 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 }} } | ... | ... |
... | ... | @@ -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 @@ |
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 | ... | ... |