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 |