Commit 94247db42f5e230f84031f2dd3d294b305889148

Authored by Luke Baker
1 parent 2372de54

retab spacing Question

Showing 1 changed file with 211 additions and 211 deletions   Show diff stats
app/models/question.rb
... ... @@ -36,7 +36,7 @@ class Question < ActiveRecord::Base
36 36 def create_choices_from_ideas
37 37 if ideas && ideas.any?
38 38 ideas.each do |idea|
39   - choices.create!(:creator => self.creator, :active => true, :data => idea.squish.strip)
  39 + choices.create!(:creator => self.creator, :active => true, :data => idea.squish.strip)
40 40 end
41 41 end
42 42 end
... ... @@ -48,27 +48,27 @@ class Question < ActiveRecord::Base
48 48 def choose_prompt(options = {})
49 49  
50 50 # if there is one or fewer active choices, we won't be able to find a prompt
51   - if self.choices.size - self.inactive_choices_count <= 1
52   - raise RuntimeError, "More than one choice needs to be active"
53   - end
54   -
55   - if self.uses_catchup? || options[:algorithm] == "catchup"
56   - logger.info("Question #{self.id} is using catchup algorithm!")
57   - next_prompt = self.pop_prompt_queue
58   - if next_prompt.nil?
59   - logger.info("DEBUG Catchup prompt cache miss! Nothing in prompt_queue")
60   - next_prompt = self.catchup_choose_prompt
61   - record_prompt_cache_miss
62   - else
63   - record_prompt_cache_hit
64   - end
65   - self.send_later :add_prompt_to_queue
66   - return next_prompt
67   - else
68   - #Standard choose prompt at random
  51 + if self.choices.size - self.inactive_choices_count <= 1
  52 + raise RuntimeError, "More than one choice needs to be active"
  53 + end
  54 +
  55 + if self.uses_catchup? || options[:algorithm] == "catchup"
  56 + logger.info("Question #{self.id} is using catchup algorithm!")
  57 + next_prompt = self.pop_prompt_queue
  58 + if next_prompt.nil?
  59 + logger.info("DEBUG Catchup prompt cache miss! Nothing in prompt_queue")
  60 + next_prompt = self.catchup_choose_prompt
  61 + record_prompt_cache_miss
  62 + else
  63 + record_prompt_cache_hit
  64 + end
  65 + self.send_later :add_prompt_to_queue
  66 + return next_prompt
  67 + else
  68 + #Standard choose prompt at random
69 69 next_prompt = self.picked_prompt
70   - return next_prompt
71   - end
  70 + return next_prompt
  71 + end
72 72  
73 73 end
74 74  
... ... @@ -92,16 +92,16 @@ class Question &lt; ActiveRecord::Base
92 92 prompt = nil
93 93  
94 94 until prompt && prompt.active?
95   - target = rand
96   - left_choice_id = right_choice_id = nil
97   -
98   - weighted.each do |item, weight|
99   - if target <= weight
100   - left_choice_id, right_choice_id = item.split(", ")
101   - break
102   - end
103   - target -= weight
104   - end
  95 + target = rand
  96 + left_choice_id = right_choice_id = nil
  97 +
  98 + weighted.each do |item, weight|
  99 + if target <= weight
  100 + left_choice_id, right_choice_id = item.split(", ")
  101 + break
  102 + end
  103 + target -= weight
  104 + end
105 105 prompt = prompts.find_or_create_by_left_choice_id_and_right_choice_id(left_choice_id, right_choice_id, :include => [{ :left_choice => :item }, { :right_choice => :item }])
106 106 end
107 107 # check if prompt has two active choices here, maybe we can set this on the prompt level too?
... ... @@ -116,24 +116,24 @@ class Question &lt; ActiveRecord::Base
116 116 sum = 0.0
117 117  
118 118 prompts.find_each(:select => 'votes_count, left_choice_id, right_choice_id') do |p|
119   - value = [(1.0/ (p.votes.size + 1).to_f).to_f, throttle_min].min
  119 + value = [(1.0/ (p.votes.size + 1).to_f).to_f, throttle_min].min
120 120 weights["#{p.left_choice_id}, #{p.right_choice_id}"] = value
121   - sum += value
  121 + sum += value
122 122 end
123 123  
124 124 # This will not run once all prompts have been generated,
125   - # but it prevents us from having to pregenerate all possible prompts
  125 + # but it prevents us from having to pregenerate all possible prompts
126 126 if weights.size < choices.size ** 2 - choices.size
127 127 choices.each do |l|
128   - choices.each do |r|
129   - if l.id == r.id
130   - next
131   - end
132   - if !weights.has_key?("#{l.id}, #{r.id}")
  128 + choices.each do |r|
  129 + if l.id == r.id
  130 + next
  131 + end
  132 + if !weights.has_key?("#{l.id}, #{r.id}")
133 133 weights["#{l.id}, #{r.id}"] = throttle_min
134   - sum+=throttle_min
135   - end
136   - end
  134 + sum+=throttle_min
  135 + end
  136 + end
137 137 end
138 138 end
139 139  
... ... @@ -160,37 +160,37 @@ class Question &lt; ActiveRecord::Base
160 160 @prompt = choose_prompt(:algorithm => params[:algorithm])
161 161 @appearance = current_user.record_appearance(visitor, @prompt)
162 162 else
163   - #only display a new prompt and new appearance if the old prompt has not been voted on
164   - @appearance = last_appearance
  163 + #only display a new prompt and new appearance if the old prompt has not been voted on
  164 + @appearance = last_appearance
165 165 @prompt= @appearance.prompt
166 166 end
167 167  
168 168 if params[:future_prompts]
169   - num_future = params[:future_prompts][:number].to_i rescue 1
170   - num_future.times do |number|
171   - offset = number + 1
  169 + num_future = params[:future_prompts][:number].to_i rescue 1
  170 + num_future.times do |number|
  171 + offset = number + 1
172 172 last_appearance = get_first_unanswered_appearance(visitor, offset)
173 173 if last_appearance.nil?
174 174 @future_prompt = choose_prompt(:algorithm => params[:algorithm])
175 175 @future_appearance = current_user.record_appearance(visitor, @future_prompt)
176   - else
177   - @future_appearance = last_appearance
  176 + else
  177 + @future_appearance = last_appearance
178 178 @future_prompt= @future_appearance.prompt
179   - end
180   -
  179 + end
  180 +
181 181 result.merge!({"future_appearance_id_#{offset}".to_sym => @future_appearance.lookup})
182 182 result.merge!({"future_prompt_id_#{offset}".to_sym => @future_prompt.id})
183 183  
184   - ["left", "right"].each do |side|
185   - ["text", "id"].each do |param|
186   - choice = (side == "left") ? @future_prompt.left_choice : @future_prompt.right_choice
187   - param_val = (param == "text") ? choice.data : choice.id
  184 + ["left", "right"].each do |side|
  185 + ["text", "id"].each do |param|
  186 + choice = (side == "left") ? @future_prompt.left_choice : @future_prompt.right_choice
  187 + param_val = (param == "text") ? choice.data : choice.id
188 188  
189 189 result.merge!({"future_#{side}_choice_#{param}_#{offset}".to_sym => param_val})
190   - end
191   - end
192   -
193   - end
  190 + end
  191 + end
  192 +
  193 + end
194 194  
195 195 end
196 196  
... ... @@ -219,7 +219,7 @@ class Question &lt; ActiveRecord::Base
219 219 if votes_by_visitors.size > 0
220 220 average = votes_by_visitors.inject(0){|total, (k,v)| total = total + v}.to_f / votes_by_visitors.size.to_f
221 221 else
222   - average = 0.0
  222 + average = 0.0
223 223 end
224 224  
225 225 result.merge!(:average_votes => average.round) # round to 2 decimals
... ... @@ -232,22 +232,22 @@ class Question &lt; ActiveRecord::Base
232 232 #passing precomputed sum saves us a traversal through the array
233 233 def normalize!(weighted, sum=nil)
234 234 if weighted.instance_of?(Hash)
235   - if sum.nil?
236   - sum = weighted.inject(0) do |sum, item_and_weight|
237   - sum += item_and_weight[1]
238   - end
239   - sum = sum.to_f
240   - end
241   - weighted.each do |item, weight|
242   - weighted[item] = weight/sum
243   - weighted[item] = 0.0 unless weighted[item].finite?
244   - end
  235 + if sum.nil?
  236 + sum = weighted.inject(0) do |sum, item_and_weight|
  237 + sum += item_and_weight[1]
  238 + end
  239 + sum = sum.to_f
  240 + end
  241 + weighted.each do |item, weight|
  242 + weighted[item] = weight/sum
  243 + weighted[item] = 0.0 unless weighted[item].finite?
  244 + end
245 245 elsif weighted.instance_of?(Array)
246   - sum = weighted.inject(0) {|sum, item| sum += item} if sum.nil?
247   - weighted.each_with_index do |item, i|
248   - weighted[i] = item/sum
249   - weighted[i] = 0.0 unless weighted[i].finite?
250   - end
  246 + sum = weighted.inject(0) {|sum, item| sum += item} if sum.nil?
  247 + weighted.each_with_index do |item, i|
  248 + weighted[i] = item/sum
  249 + weighted[i] = 0.0 unless weighted[i].finite?
  250 + end
251 251  
252 252 end
253 253 end
... ... @@ -266,8 +266,8 @@ class Question &lt; ActiveRecord::Base
266 266  
267 267 # Initial probabilities chosen at random
268 268 the_choices.size.times do
269   - probs << rand
270   - prev_probs << rand
  269 + probs << rand
  270 + prev_probs << rand
271 271 end
272 272  
273 273 t=0
... ... @@ -287,13 +287,13 @@ class Question &lt; ActiveRecord::Base
287 287  
288 288 denominator = 0.0
289 289 the_choices.each_with_index do |c, index|
290   - if(index == s)
291   - next
292   - end
  290 + if(index == s)
  291 + next
  292 + end
293 293  
294   - wins_and_losses = the_prompts["#{choice.id}, #{c.id}"].votes.size + the_prompts["#{c.id}, #{choice.id}"].votes.size
  294 + wins_and_losses = the_prompts["#{choice.id}, #{c.id}"].votes.size + the_prompts["#{c.id}, #{choice.id}"].votes.size
295 295  
296   - denominator+= (wins_and_losses).to_f / (prev_probs[s] + prev_probs[index])
  296 + denominator+= (wins_and_losses).to_f / (prev_probs[s] + prev_probs[index])
297 297 end
298 298 probs[s] = numerator / denominator
299 299 # avoid divide by zero NaN
... ... @@ -303,25 +303,25 @@ class Question &lt; ActiveRecord::Base
303 303  
304 304 difference = 0
305 305 probs.each_with_index do |curr, index|
306   - difference += (curr - prev_probs[index]).abs
  306 + difference += (curr - prev_probs[index]).abs
307 307 end
308 308 puts difference
309 309 end
310 310  
311 311 probs_hash = {}
312 312 probs.each_with_index do |item, index|
313   - probs_hash[the_choices[index].id] = item
  313 + probs_hash[the_choices[index].id] = item
314 314 end
315 315 probs_hash
316 316 end
317 317  
318 318  
319 319 def all_bt_scores
320   - btprobs = bradley_terry_probs
321   - btprobs.each do |key, value|
322   - c = Choice.find(key)
323   - puts "#{c.id}: #{c.votes.size} #{c.compute_bt_score(btprobs)}"
324   - end
  320 + btprobs = bradley_terry_probs
  321 + btprobs.each do |key, value|
  322 + c = Choice.find(key)
  323 + puts "#{c.id}: #{c.votes.size} #{c.compute_bt_score(btprobs)}"
  324 + end
325 325  
326 326 end
327 327  
... ... @@ -388,36 +388,36 @@ class Question &lt; ActiveRecord::Base
388 388  
389 389 is_user_created = {}
390 390 self.choices.each do |c|
391   - is_user_created[c.id] = c.user_created
  391 + is_user_created[c.id] = c.user_created
392 392 end
393 393  
394 394  
395 395 #the_prompts = prompts.find(:all, :include => ['left_choice', 'right_choice'])
396 396 prompts.find_each do |p|
397 397  
398   - num_appearances = num_appearances_by_prompt[p.id]
399   -
400   - if num_appearances.nil?
401   - num_appearances = 0
402   - end
403   -
404   - left_user_created = is_user_created[p.left_choice_id]
405   - right_user_created = is_user_created[p.right_choice_id]
406   -
407   -
408   - if left_user_created == false && right_user_created == false
409   - seed_seed_sum += num_appearances
410   - seed_seed_total +=1
411   - elsif left_user_created == false && right_user_created == true
412   - seed_nonseed_sum += num_appearances
413   - seed_nonseed_total +=1
414   - elsif left_user_created == true && right_user_created == false
415   - nonseed_seed_sum += num_appearances
416   - nonseed_seed_total +=1
417   - elsif left_user_created == true && right_user_created == true
418   - nonseed_nonseed_sum += num_appearances
419   - nonseed_nonseed_total +=1
420   - end
  398 + num_appearances = num_appearances_by_prompt[p.id]
  399 +
  400 + if num_appearances.nil?
  401 + num_appearances = 0
  402 + end
  403 +
  404 + left_user_created = is_user_created[p.left_choice_id]
  405 + right_user_created = is_user_created[p.right_choice_id]
  406 +
  407 +
  408 + if left_user_created == false && right_user_created == false
  409 + seed_seed_sum += num_appearances
  410 + seed_seed_total +=1
  411 + elsif left_user_created == false && right_user_created == true
  412 + seed_nonseed_sum += num_appearances
  413 + seed_nonseed_total +=1
  414 + elsif left_user_created == true && right_user_created == false
  415 + nonseed_seed_sum += num_appearances
  416 + nonseed_seed_total +=1
  417 + elsif left_user_created == true && right_user_created == true
  418 + nonseed_nonseed_sum += num_appearances
  419 + nonseed_nonseed_total +=1
  420 + end
421 421 end
422 422  
423 423 densities = {}
... ... @@ -437,175 +437,175 @@ class Question &lt; ActiveRecord::Base
437 437  
438 438 def save_densities!
439 439  
440   - d_hash = density
  440 + d_hash = density
441 441  
442   - d_hash.each do |type, average|
443   - d = Density.new
444   - d.question_id = self.id
445   - d.prompt_type = type.to_s
446   - d.value = average.nan? ? nil : average
447   - d.save!
448   - end
  442 + d_hash.each do |type, average|
  443 + d = Density.new
  444 + d.question_id = self.id
  445 + d.prompt_type = type.to_s
  446 + d.value = average.nan? ? nil : average
  447 + d.save!
  448 + end
449 449 end
450 450  
451 451 def pq_key
452   - @pq_key ||= "#{self.id}_prompt_queue"
  452 + @pq_key ||= "#{self.id}_prompt_queue"
453 453 end
454 454  
455 455 def clear_prompt_queue
456   - $redis.del(self.pq_key)
  456 + $redis.del(self.pq_key)
457 457 end
458 458  
459 459 def add_prompt_to_queue
460   - prompt = self.catchup_choose_prompt
461   - $redis.rpush(self.pq_key, prompt.id)
462   - prompt
  460 + prompt = self.catchup_choose_prompt
  461 + $redis.rpush(self.pq_key, prompt.id)
  462 + prompt
463 463 end
464 464  
465 465 def pop_prompt_queue
466   - begin
467   - prompt_id = $redis.lpop(self.pq_key)
468   - prompt = prompt_id.nil? ? nil : Prompt.find(prompt_id.to_i)
  466 + begin
  467 + prompt_id = $redis.lpop(self.pq_key)
  468 + prompt = prompt_id.nil? ? nil : Prompt.find(prompt_id.to_i)
469 469 end until (prompt.nil? || prompt.active?)
470 470 prompt
471 471 end
472 472  
473 473 def record_prompt_cache_miss
474   - $redis.incr(self.pq_key + "_" + Time.now.to_date.to_s + "_"+ "misses")
  474 + $redis.incr(self.pq_key + "_" + Time.now.to_date.to_s + "_"+ "misses")
475 475 end
476 476  
477 477 def record_prompt_cache_hit
478   - $redis.incr(self.pq_key + "_" + Time.now.to_date.to_s + "_"+ "hits")
  478 + $redis.incr(self.pq_key + "_" + Time.now.to_date.to_s + "_"+ "hits")
479 479 end
480 480  
481 481 def get_prompt_cache_misses(date)
482   - $redis.get(self.pq_key + "_" + date.to_s + "_"+ "misses")
  482 + $redis.get(self.pq_key + "_" + date.to_s + "_"+ "misses")
483 483 end
484 484 def get_prompt_cache_hits(date)
485   - $redis.get(self.pq_key + "_" + date.to_s + "_"+ "hits")
  485 + $redis.get(self.pq_key + "_" + date.to_s + "_"+ "hits")
486 486 end
487 487  
488 488 def reset_cache_tracking_keys(date)
489   - $redis.del(self.pq_key + "_" + date.to_s + "_"+ "misses")
490   - $redis.del(self.pq_key + "_" + date.to_s + "_"+ "hits")
  489 + $redis.del(self.pq_key + "_" + date.to_s + "_"+ "misses")
  490 + $redis.del(self.pq_key + "_" + date.to_s + "_"+ "hits")
491 491 end
492 492  
493 493  
494 494 def expire_prompt_cache_tracking_keys(date, expire_time = 24*60*60 * 3) # default expires in three days
495   - $redis.expire(self.pq_key + "_" + date.to_s + "_"+ "hits", expire_time)
496   - $redis.expire(self.pq_key + "_" + date.to_s + "_"+ "misses", expire_time)
  495 + $redis.expire(self.pq_key + "_" + date.to_s + "_"+ "hits", expire_time)
  496 + $redis.expire(self.pq_key + "_" + date.to_s + "_"+ "misses", expire_time)
497 497 end
498 498  
499 499  
500 500 def export_and_delete(type, options={})
501   - delete_at = options.delete(:delete_at)
502   - filename = export(type, options)
  501 + delete_at = options.delete(:delete_at)
  502 + filename = export(type, options)
503 503  
504   - File.send_at(delete_at, :delete, filename)
505   - filename
  504 + File.send_at(delete_at, :delete, filename)
  505 + filename
506 506 end
507 507  
508 508 def export(type, options = {})
509 509  
510 510 case type
511 511 when 'votes'
512   - outfile = "ideamarketplace_#{self.id}_votes.csv"
  512 + outfile = "ideamarketplace_#{self.id}_votes.csv"
513 513  
514   - headers = ['Vote ID', 'Session ID', 'Question ID','Winner ID', 'Winner Text', 'Loser ID', 'Loser Text',
515   - 'Prompt ID', 'Left Choice ID', 'Right Choice ID', 'Created at', 'Updated at', 'Appearance ID',
516   - 'Response Time (s)', 'Missing Response Time Explanation', 'Session Identifier']
  514 + headers = ['Vote ID', 'Session ID', 'Question ID','Winner ID', 'Winner Text', 'Loser ID', 'Loser Text',
  515 + 'Prompt ID', 'Left Choice ID', 'Right Choice ID', 'Created at', 'Updated at', 'Appearance ID',
  516 + 'Response Time (s)', 'Missing Response Time Explanation', 'Session Identifier']
517 517  
518 518 when 'ideas'
519   - outfile = "ideamarketplace_#{self.id}_ideas.csv"
  519 + outfile = "ideamarketplace_#{self.id}_ideas.csv"
520 520 headers = ['Ideamarketplace ID','Idea ID', 'Idea Text', 'Wins', 'Losses', 'Times involved in Cant Decide', 'Score',
521   - 'User Submitted', 'Session ID', 'Created at', 'Last Activity', 'Active',
522   - 'Appearances on Left', 'Appearances on Right']
  521 + 'User Submitted', 'Session ID', 'Created at', 'Last Activity', 'Active',
  522 + 'Appearances on Left', 'Appearances on Right']
523 523 when 'non_votes'
524 524 outfile = "ideamarketplace_#{self.id}_non_votes.csv"
525 525 headers = ['Record Type', 'Record ID', 'Session ID', 'Question ID','Left Choice ID', 'Left Choice Text',
526   - 'Right Choice ID', 'Right Choice Text', 'Prompt ID', 'Appearance ID', 'Reason',
527   - 'Created at', 'Updated at', 'Response Time (s)', 'Missing Response Time Explanation', 'Session Identifier']
  526 + 'Right Choice ID', 'Right Choice Text', 'Prompt ID', 'Appearance ID', 'Reason',
  527 + 'Created at', 'Updated at', 'Response Time (s)', 'Missing Response Time Explanation', 'Session Identifier']
528 528 else
529   - raise "Unsupported export type: #{type}"
  529 + raise "Unsupported export type: #{type}"
530 530 end
531 531  
532 532 filename = File.join(File.expand_path(Rails.root), "public", "system", "exports",
533   - self.id.to_s, Digest::SHA1.hexdigest(outfile + rand(10000000).to_s) + "_" + outfile)
  533 + self.id.to_s, Digest::SHA1.hexdigest(outfile + rand(10000000).to_s) + "_" + outfile)
534 534  
535 535 FileUtils::mkdir_p(File.dirname(filename))
536 536 csv_data = FasterCSV.open(filename, "w") do |csv|
537   - csv << headers
  537 + csv << headers
538 538  
539 539 case type
540 540 when 'votes'
541 541  
542 542 self.votes.find_each(:include => [:prompt, :choice, :loser_choice, :voter]) do |v|
543   - prompt = v.prompt
544   - # these may not exist
545   - loser_data = v.loser_choice.nil? ? "" : "'#{v.loser_choice.data.strip}'"
546   - left_id = v.prompt.nil? ? "" : v.prompt.left_choice_id
547   - right_id = v.prompt.nil? ? "" : v.prompt.right_choice_id
  543 + prompt = v.prompt
  544 + # these may not exist
  545 + loser_data = v.loser_choice.nil? ? "" : "'#{v.loser_choice.data.strip}'"
  546 + left_id = v.prompt.nil? ? "" : v.prompt.left_choice_id
  547 + right_id = v.prompt.nil? ? "" : v.prompt.right_choice_id
548 548  
549   - time_viewed = v.time_viewed.nil? ? "NA": v.time_viewed.to_f / 1000.0
  549 + time_viewed = v.time_viewed.nil? ? "NA": v.time_viewed.to_f / 1000.0
550 550  
551   - csv << [ v.id, v.voter_id, v.question_id, v.choice_id, "'#{v.choice.data.strip}'", v.loser_choice_id, loser_data,
552   - v.prompt_id, left_id, right_id, v.created_at, v.updated_at, v.appearance_id,
553   - time_viewed, v.missing_response_time_exp , v.voter.identifier]
554   - end
  551 + csv << [ v.id, v.voter_id, v.question_id, v.choice_id, "'#{v.choice.data.strip}'", v.loser_choice_id, loser_data,
  552 + v.prompt_id, left_id, right_id, v.created_at, v.updated_at, v.appearance_id,
  553 + time_viewed, v.missing_response_time_exp , v.voter.identifier]
  554 + end
555 555  
556 556 when 'ideas'
557 557 self.choices.each do |c|
558 558 user_submitted = c.user_created ? "TRUE" : "FALSE"
559   - left_prompts_ids = c.prompts_on_the_left.ids_only
560   - right_prompts_ids = c.prompts_on_the_right.ids_only
  559 + left_prompts_ids = c.prompts_on_the_left.ids_only
  560 + right_prompts_ids = c.prompts_on_the_right.ids_only
561 561  
562   - left_appearances = self.appearances.count(:conditions => {:prompt_id => left_prompts_ids})
563   - right_appearances = self.appearances.count(:conditions => {:prompt_id => right_prompts_ids})
  562 + left_appearances = self.appearances.count(:conditions => {:prompt_id => left_prompts_ids})
  563 + right_appearances = self.appearances.count(:conditions => {:prompt_id => right_prompts_ids})
564 564  
565   - num_skips = self.skips.count(:conditions => {:prompt_id => left_prompts_ids + right_prompts_ids})
  565 + num_skips = self.skips.count(:conditions => {:prompt_id => left_prompts_ids + right_prompts_ids})
566 566  
567   - csv << [c.question_id, c.id, "'#{c.data.strip}'", c.wins, c.losses, num_skips, c.score,
568   - user_submitted , c.creator_id, c.created_at, c.updated_at, c.active,
569   - left_appearances, right_appearances]
  567 + csv << [c.question_id, c.id, "'#{c.data.strip}'", c.wins, c.losses, num_skips, c.score,
  568 + user_submitted , c.creator_id, c.created_at, c.updated_at, c.active,
  569 + left_appearances, right_appearances]
570 570 end
571 571 when 'non_votes'
572   -
573   - self.appearances.find_each(:include => [:skip, :vote, :voter]) do |a|
574   - # we only display skips and orphaned appearances in this csv file
575   - unless a.vote.nil?
576   - next
577   - end
578   -
579   - #If no skip and no vote, this is an orphaned appearance
580   - if a.skip.nil?
581   - prompt = a.prompt
582   - csv << [ "Orphaned Appearance", a.id, a.voter_id, a.question_id, a.prompt.left_choice.id, a.prompt.left_choice.data.strip,
583   - a.prompt.right_choice.id, a.prompt.right_choice.data.strip, a.prompt_id, 'N/A', 'N/A',
584   - a.created_at, a.updated_at, 'N/A', '', a.voter.identifier]
585   -
586   - else
587   -
588   - #If this appearance belongs to a skip, show information on the skip instead
589   - s = a.skip
590   - time_viewed = s.time_viewed.nil? ? "NA": s.time_viewed.to_f / 1000.0
591   - prompt = s.prompt
592   - csv << [ "Skip", s.id, s.skipper_id, s.question_id, s.prompt.left_choice.id, s.prompt.left_choice.data.strip,
593   - s.prompt.right_choice.id, s.prompt.right_choice.data.strip, s.prompt_id, s.appearance_id, s.skip_reason,
594   - s.created_at, s.updated_at, time_viewed , s.missing_response_time_exp, s.skipper.identifier]
595   - end
596   - end
  572 +
  573 + self.appearances.find_each(:include => [:skip, :vote, :voter]) do |a|
  574 + # we only display skips and orphaned appearances in this csv file
  575 + unless a.vote.nil?
  576 + next
  577 + end
  578 +
  579 + #If no skip and no vote, this is an orphaned appearance
  580 + if a.skip.nil?
  581 + prompt = a.prompt
  582 + csv << [ "Orphaned Appearance", a.id, a.voter_id, a.question_id, a.prompt.left_choice.id, a.prompt.left_choice.data.strip,
  583 + a.prompt.right_choice.id, a.prompt.right_choice.data.strip, a.prompt_id, 'N/A', 'N/A',
  584 + a.created_at, a.updated_at, 'N/A', '', a.voter.identifier]
  585 +
  586 + else
  587 +
  588 + #If this appearance belongs to a skip, show information on the skip instead
  589 + s = a.skip
  590 + time_viewed = s.time_viewed.nil? ? "NA": s.time_viewed.to_f / 1000.0
  591 + prompt = s.prompt
  592 + csv << [ "Skip", s.id, s.skipper_id, s.question_id, s.prompt.left_choice.id, s.prompt.left_choice.data.strip,
  593 + s.prompt.right_choice.id, s.prompt.right_choice.data.strip, s.prompt_id, s.appearance_id, s.skip_reason,
  594 + s.created_at, s.updated_at, time_viewed , s.missing_response_time_exp, s.skipper.identifier]
  595 + end
  596 + end
597 597 end
598 598  
599 599 end
600 600  
601 601 if options[:response_type] == 'redis'
602 602  
603   - if options[:redis_key].nil?
604   - raise "No :redis_key specified"
605   - end
606   - #The client should use blpop to listen for a key
607   - #The client is responsible for deleting the redis key (auto expiration results failure in testing)
608   - $redis.lpush(options[:redis_key], filename)
  603 + if options[:redis_key].nil?
  604 + raise "No :redis_key specified"
  605 + end
  606 + #The client should use blpop to listen for a key
  607 + #The client is responsible for deleting the redis key (auto expiration results failure in testing)
  608 + $redis.lpush(options[:redis_key], filename)
609 609 #TODO implement response_type == 'email' for use by customers of the API (not local)
610 610 end
611 611  
... ... @@ -614,17 +614,17 @@ class Question &lt; ActiveRecord::Base
614 614  
615 615 def get_first_unanswered_appearance(visitor, offset=0)
616 616 last_appearance = visitor.appearances.find(:first,
617   - :conditions => {:question_id => self.id,
618   - :answerable_id => nil
619   - },
620   - :order => 'id ASC',
621   - :offset => offset)
  617 + :conditions => {:question_id => self.id,
  618 + :answerable_id => nil
  619 + },
  620 + :order => 'id ASC',
  621 + :offset => offset)
622 622 if last_appearance && !last_appearance.prompt.active?
623   - last_appearance.valid_record = false
624   - last_appearance.validity_information = "Deactivated Prompt"
625   - last_appearance.save
  623 + last_appearance.valid_record = false
  624 + last_appearance.validity_information = "Deactivated Prompt"
  625 + last_appearance.save
626 626  
627   - return get_first_unanswered_appearance(visitor)
  627 + return get_first_unanswered_appearance(visitor)
628 628 end
629 629 last_appearance
630 630 end
... ...