Commit 94247db42f5e230f84031f2dd3d294b305889148
1 parent
2372de54
Exists in
master
and in
1 other branch
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,7 +36,7 @@ class Question < ActiveRecord::Base | ||
36 | def create_choices_from_ideas | 36 | def create_choices_from_ideas |
37 | if ideas && ideas.any? | 37 | if ideas && ideas.any? |
38 | ideas.each do |idea| | 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 | end | 40 | end |
41 | end | 41 | end |
42 | end | 42 | end |
@@ -48,27 +48,27 @@ class Question < ActiveRecord::Base | @@ -48,27 +48,27 @@ class Question < ActiveRecord::Base | ||
48 | def choose_prompt(options = {}) | 48 | def choose_prompt(options = {}) |
49 | 49 | ||
50 | # if there is one or fewer active choices, we won't be able to find a prompt | 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 | next_prompt = self.picked_prompt | 69 | next_prompt = self.picked_prompt |
70 | - return next_prompt | ||
71 | - end | 70 | + return next_prompt |
71 | + end | ||
72 | 72 | ||
73 | end | 73 | end |
74 | 74 | ||
@@ -92,16 +92,16 @@ class Question < ActiveRecord::Base | @@ -92,16 +92,16 @@ class Question < ActiveRecord::Base | ||
92 | prompt = nil | 92 | prompt = nil |
93 | 93 | ||
94 | until prompt && prompt.active? | 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 | 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 }]) | 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 | end | 106 | end |
107 | # check if prompt has two active choices here, maybe we can set this on the prompt level too? | 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 < ActiveRecord::Base | @@ -116,24 +116,24 @@ class Question < ActiveRecord::Base | ||
116 | sum = 0.0 | 116 | sum = 0.0 |
117 | 117 | ||
118 | prompts.find_each(:select => 'votes_count, left_choice_id, right_choice_id') do |p| | 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 | weights["#{p.left_choice_id}, #{p.right_choice_id}"] = value | 120 | weights["#{p.left_choice_id}, #{p.right_choice_id}"] = value |
121 | - sum += value | 121 | + sum += value |
122 | end | 122 | end |
123 | 123 | ||
124 | # This will not run once all prompts have been generated, | 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 | if weights.size < choices.size ** 2 - choices.size | 126 | if weights.size < choices.size ** 2 - choices.size |
127 | choices.each do |l| | 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 | weights["#{l.id}, #{r.id}"] = throttle_min | 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 | end | 137 | end |
138 | end | 138 | end |
139 | 139 | ||
@@ -160,37 +160,37 @@ class Question < ActiveRecord::Base | @@ -160,37 +160,37 @@ class Question < ActiveRecord::Base | ||
160 | @prompt = choose_prompt(:algorithm => params[:algorithm]) | 160 | @prompt = choose_prompt(:algorithm => params[:algorithm]) |
161 | @appearance = current_user.record_appearance(visitor, @prompt) | 161 | @appearance = current_user.record_appearance(visitor, @prompt) |
162 | else | 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 | @prompt= @appearance.prompt | 165 | @prompt= @appearance.prompt |
166 | end | 166 | end |
167 | 167 | ||
168 | if params[:future_prompts] | 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 | last_appearance = get_first_unanswered_appearance(visitor, offset) | 172 | last_appearance = get_first_unanswered_appearance(visitor, offset) |
173 | if last_appearance.nil? | 173 | if last_appearance.nil? |
174 | @future_prompt = choose_prompt(:algorithm => params[:algorithm]) | 174 | @future_prompt = choose_prompt(:algorithm => params[:algorithm]) |
175 | @future_appearance = current_user.record_appearance(visitor, @future_prompt) | 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 | @future_prompt= @future_appearance.prompt | 178 | @future_prompt= @future_appearance.prompt |
179 | - end | ||
180 | - | 179 | + end |
180 | + | ||
181 | result.merge!({"future_appearance_id_#{offset}".to_sym => @future_appearance.lookup}) | 181 | result.merge!({"future_appearance_id_#{offset}".to_sym => @future_appearance.lookup}) |
182 | result.merge!({"future_prompt_id_#{offset}".to_sym => @future_prompt.id}) | 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 | result.merge!({"future_#{side}_choice_#{param}_#{offset}".to_sym => param_val}) | 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 | end | 195 | end |
196 | 196 | ||
@@ -219,7 +219,7 @@ class Question < ActiveRecord::Base | @@ -219,7 +219,7 @@ class Question < ActiveRecord::Base | ||
219 | if votes_by_visitors.size > 0 | 219 | if votes_by_visitors.size > 0 |
220 | average = votes_by_visitors.inject(0){|total, (k,v)| total = total + v}.to_f / votes_by_visitors.size.to_f | 220 | average = votes_by_visitors.inject(0){|total, (k,v)| total = total + v}.to_f / votes_by_visitors.size.to_f |
221 | else | 221 | else |
222 | - average = 0.0 | 222 | + average = 0.0 |
223 | end | 223 | end |
224 | 224 | ||
225 | result.merge!(:average_votes => average.round) # round to 2 decimals | 225 | result.merge!(:average_votes => average.round) # round to 2 decimals |
@@ -232,22 +232,22 @@ class Question < ActiveRecord::Base | @@ -232,22 +232,22 @@ class Question < ActiveRecord::Base | ||
232 | #passing precomputed sum saves us a traversal through the array | 232 | #passing precomputed sum saves us a traversal through the array |
233 | def normalize!(weighted, sum=nil) | 233 | def normalize!(weighted, sum=nil) |
234 | if weighted.instance_of?(Hash) | 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 | elsif weighted.instance_of?(Array) | 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 | end | 252 | end |
253 | end | 253 | end |
@@ -266,8 +266,8 @@ class Question < ActiveRecord::Base | @@ -266,8 +266,8 @@ class Question < ActiveRecord::Base | ||
266 | 266 | ||
267 | # Initial probabilities chosen at random | 267 | # Initial probabilities chosen at random |
268 | the_choices.size.times do | 268 | the_choices.size.times do |
269 | - probs << rand | ||
270 | - prev_probs << rand | 269 | + probs << rand |
270 | + prev_probs << rand | ||
271 | end | 271 | end |
272 | 272 | ||
273 | t=0 | 273 | t=0 |
@@ -287,13 +287,13 @@ class Question < ActiveRecord::Base | @@ -287,13 +287,13 @@ class Question < ActiveRecord::Base | ||
287 | 287 | ||
288 | denominator = 0.0 | 288 | denominator = 0.0 |
289 | the_choices.each_with_index do |c, index| | 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 | end | 297 | end |
298 | probs[s] = numerator / denominator | 298 | probs[s] = numerator / denominator |
299 | # avoid divide by zero NaN | 299 | # avoid divide by zero NaN |
@@ -303,25 +303,25 @@ class Question < ActiveRecord::Base | @@ -303,25 +303,25 @@ class Question < ActiveRecord::Base | ||
303 | 303 | ||
304 | difference = 0 | 304 | difference = 0 |
305 | probs.each_with_index do |curr, index| | 305 | probs.each_with_index do |curr, index| |
306 | - difference += (curr - prev_probs[index]).abs | 306 | + difference += (curr - prev_probs[index]).abs |
307 | end | 307 | end |
308 | puts difference | 308 | puts difference |
309 | end | 309 | end |
310 | 310 | ||
311 | probs_hash = {} | 311 | probs_hash = {} |
312 | probs.each_with_index do |item, index| | 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 | end | 314 | end |
315 | probs_hash | 315 | probs_hash |
316 | end | 316 | end |
317 | 317 | ||
318 | 318 | ||
319 | def all_bt_scores | 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 | end | 326 | end |
327 | 327 | ||
@@ -388,36 +388,36 @@ class Question < ActiveRecord::Base | @@ -388,36 +388,36 @@ class Question < ActiveRecord::Base | ||
388 | 388 | ||
389 | is_user_created = {} | 389 | is_user_created = {} |
390 | self.choices.each do |c| | 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 | end | 392 | end |
393 | 393 | ||
394 | 394 | ||
395 | #the_prompts = prompts.find(:all, :include => ['left_choice', 'right_choice']) | 395 | #the_prompts = prompts.find(:all, :include => ['left_choice', 'right_choice']) |
396 | prompts.find_each do |p| | 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 | end | 421 | end |
422 | 422 | ||
423 | densities = {} | 423 | densities = {} |
@@ -437,175 +437,175 @@ class Question < ActiveRecord::Base | @@ -437,175 +437,175 @@ class Question < ActiveRecord::Base | ||
437 | 437 | ||
438 | def save_densities! | 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 | end | 449 | end |
450 | 450 | ||
451 | def pq_key | 451 | def pq_key |
452 | - @pq_key ||= "#{self.id}_prompt_queue" | 452 | + @pq_key ||= "#{self.id}_prompt_queue" |
453 | end | 453 | end |
454 | 454 | ||
455 | def clear_prompt_queue | 455 | def clear_prompt_queue |
456 | - $redis.del(self.pq_key) | 456 | + $redis.del(self.pq_key) |
457 | end | 457 | end |
458 | 458 | ||
459 | def add_prompt_to_queue | 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 | end | 463 | end |
464 | 464 | ||
465 | def pop_prompt_queue | 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 | end until (prompt.nil? || prompt.active?) | 469 | end until (prompt.nil? || prompt.active?) |
470 | prompt | 470 | prompt |
471 | end | 471 | end |
472 | 472 | ||
473 | def record_prompt_cache_miss | 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 | end | 475 | end |
476 | 476 | ||
477 | def record_prompt_cache_hit | 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 | end | 479 | end |
480 | 480 | ||
481 | def get_prompt_cache_misses(date) | 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 | end | 483 | end |
484 | def get_prompt_cache_hits(date) | 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 | end | 486 | end |
487 | 487 | ||
488 | def reset_cache_tracking_keys(date) | 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 | end | 491 | end |
492 | 492 | ||
493 | 493 | ||
494 | def expire_prompt_cache_tracking_keys(date, expire_time = 24*60*60 * 3) # default expires in three days | 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 | end | 497 | end |
498 | 498 | ||
499 | 499 | ||
500 | def export_and_delete(type, options={}) | 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 | end | 506 | end |
507 | 507 | ||
508 | def export(type, options = {}) | 508 | def export(type, options = {}) |
509 | 509 | ||
510 | case type | 510 | case type |
511 | when 'votes' | 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 | when 'ideas' | 518 | when 'ideas' |
519 | - outfile = "ideamarketplace_#{self.id}_ideas.csv" | 519 | + outfile = "ideamarketplace_#{self.id}_ideas.csv" |
520 | headers = ['Ideamarketplace ID','Idea ID', 'Idea Text', 'Wins', 'Losses', 'Times involved in Cant Decide', 'Score', | 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 | when 'non_votes' | 523 | when 'non_votes' |
524 | outfile = "ideamarketplace_#{self.id}_non_votes.csv" | 524 | outfile = "ideamarketplace_#{self.id}_non_votes.csv" |
525 | headers = ['Record Type', 'Record ID', 'Session ID', 'Question ID','Left Choice ID', 'Left Choice Text', | 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 | else | 528 | else |
529 | - raise "Unsupported export type: #{type}" | 529 | + raise "Unsupported export type: #{type}" |
530 | end | 530 | end |
531 | 531 | ||
532 | filename = File.join(File.expand_path(Rails.root), "public", "system", "exports", | 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 | FileUtils::mkdir_p(File.dirname(filename)) | 535 | FileUtils::mkdir_p(File.dirname(filename)) |
536 | csv_data = FasterCSV.open(filename, "w") do |csv| | 536 | csv_data = FasterCSV.open(filename, "w") do |csv| |
537 | - csv << headers | 537 | + csv << headers |
538 | 538 | ||
539 | case type | 539 | case type |
540 | when 'votes' | 540 | when 'votes' |
541 | 541 | ||
542 | self.votes.find_each(:include => [:prompt, :choice, :loser_choice, :voter]) do |v| | 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 | when 'ideas' | 556 | when 'ideas' |
557 | self.choices.each do |c| | 557 | self.choices.each do |c| |
558 | user_submitted = c.user_created ? "TRUE" : "FALSE" | 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 | end | 570 | end |
571 | when 'non_votes' | 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 | end | 597 | end |
598 | 598 | ||
599 | end | 599 | end |
600 | 600 | ||
601 | if options[:response_type] == 'redis' | 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 | #TODO implement response_type == 'email' for use by customers of the API (not local) | 609 | #TODO implement response_type == 'email' for use by customers of the API (not local) |
610 | end | 610 | end |
611 | 611 | ||
@@ -614,17 +614,17 @@ class Question < ActiveRecord::Base | @@ -614,17 +614,17 @@ class Question < ActiveRecord::Base | ||
614 | 614 | ||
615 | def get_first_unanswered_appearance(visitor, offset=0) | 615 | def get_first_unanswered_appearance(visitor, offset=0) |
616 | last_appearance = visitor.appearances.find(:first, | 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 | if last_appearance && !last_appearance.prompt.active? | 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 | end | 628 | end |
629 | last_appearance | 629 | last_appearance |
630 | end | 630 | end |