diff --git a/app/models/choice.rb b/app/models/choice.rb index 7b5edb6..1f645f6 100644 --- a/app/models/choice.rb +++ b/app/models/choice.rb @@ -44,7 +44,7 @@ class Choice < ActiveRecord::Base votes_count || 0 end - #after_create :generate_prompts + after_create :generate_prompts def before_create puts "just got inside choice#before_create. is set to active? #{self.active?}" unless item @@ -90,9 +90,31 @@ class Choice < ActiveRecord::Base #do this in a new process (via delayed jobs) previous_choices = (self.question.choices - [self]) return if previous_choices.empty? - previous_choices.each { |c| - question.prompts.create!(:left_choice => c, :right_choice => self) - question.prompts.create!(:left_choice => self, :right_choice => c) - } + inserts = [] + + timestring = Time.now.to_s(:db) #isn't rails awesome? + + #add prompts with this choice on the left + previous_choices.each do |r| + inserts.push("(NULL, #{self.question_id}, NULL, #{self.id}, '#{timestring}', '#{timestring}', NULL, 0, #{r.id}, NULL, NULL)") + end + #add prompts with this choice on the right + previous_choices.each do |l| + inserts.push("(NULL, #{self.question_id}, NULL, #{l.id}, '#{timestring}', '#{timestring}', NULL, 0, #{self.id}, NULL, NULL)") + end + sql = "INSERT INTO `prompts` (`algorithm_id`, `question_id`, `voter_id`, `left_choice_id`, `created_at`, `updated_at`, `tracking`, `votes_count`, `right_choice_id`, `active`, `randomkey`) VALUES #{inserts.join(', ')}" + + Question.update_counters(self.question_id, :prompts_count => 2*previous_choices.size) + + logger.info("The sql is:::: #{sql}") + + ActiveRecord::Base.connection.execute(sql) + +#VALUES (NULL, 108, NULL, 1892, '2010-03-16 11:12:37', '2010-03-16 11:12:37', NULL, 0, 1893, NULL, NULL) +# INSERT INTO `prompts` (`algorithm_id`, `question_id`, `voter_id`, `left_choice_id`, `created_at`, `updated_at`, `tracking`, `votes_count`, `right_choice_id`, `active`, `randomkey`) VALUES(NULL, 108, NULL, 1892, '2010-03-16 11:12:37', '2010-03-16 11:12:37', NULL, 0, 1893, NULL, NULL) + #previous_choices.each { |c| + # question.prompts.create!(:left_choice => c, :right_choice => self) + # question.prompts.create!(:left_choice => self, :right_choice => c) + #} end end diff --git a/app/models/prompt.rb b/app/models/prompt.rb index 122df5c..de6e4f8 100644 --- a/app/models/prompt.rb +++ b/app/models/prompt.rb @@ -38,14 +38,6 @@ class Prompt < ActiveRecord::Base left_choice.item.data end - def left_choice_id - left_choice.id - end - - def right_choice_id - right_choice.id - end - def active? left_choice.active? and right_choice.active? end diff --git a/app/models/question.rb b/app/models/question.rb index 624a72f..5f58e20 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -37,6 +37,44 @@ class Question < ActiveRecord::Base end until @p.active? return @p end + + # adapted from ruby cookbook(2006): section 5-11 + def catchup_choose_prompt_id + weighted = catchup_prompts_weights + # Rand returns a number from 0 - 1, so weighted needs to be normalized + target = rand + weighted.each do |item, weight| + return item if target <= weight + target -= weight + end + # check if prompt has two active choices here, maybe we can set this on the prompt level too? + end + + + # TODO Add index for question id on prompts table + def catchup_prompts_weights + weights = Hash.new(0) + throttle_min = 0.05 + #assuming all prompts exist + prompts.each do |p| + weights[p.id] = [(1.0/ (p.votes.size + 1).to_f).to_f, throttle_min].min + end + normalize!(weights) + weights + end + + def normalize!(weighted) + if weighted.instance_of?(Hash) + sum = weighted.inject(0) do |sum, item_and_weight| + sum += item_and_weight[1] + end + sum = sum.to_f + weighted.each { |item, weight| weighted[item] = weight/sum } + elsif weighted.instance_of?(Array) + sum = weighted.inject(0) {|sum, item| sum += item} + weighted.each_with_index {|item, i| weighted[i] = item/sum} + end + end def distinct_array_of_choice_ids(rank = 2, only_active = true) @choice_ids = choice_ids diff --git a/db/migrate/20100317161212_add_question_index_to_prompts.rb b/db/migrate/20100317161212_add_question_index_to_prompts.rb new file mode 100644 index 0000000..a66491c --- /dev/null +++ b/db/migrate/20100317161212_add_question_index_to_prompts.rb @@ -0,0 +1,9 @@ +class AddQuestionIndexToPrompts < ActiveRecord::Migration + def self.up + add_index :prompts, :question_id + end + + def self.down + remove_index :prompts, :question_id + end +end diff --git a/lib/tasks/test_api.rake b/lib/tasks/test_api.rake index e963f3d..2066080 100644 --- a/lib/tasks/test_api.rake +++ b/lib/tasks/test_api.rake @@ -1,7 +1,112 @@ +require 'fastercsv' namespace :test_api do task :all => [:question_vote_consistency] + desc "Don't run unless you know what you are doing" + task(:generate_lots_of_votes => :environment) do + if Rails.env.production? + print "You probably don't want to run this in production as it will falsify a bunch of random votes" + end + + + current_user = User.first + 3000.times do + question = Question.find(120) # test question change as needed + @p = Prompt.find(question.catchup_choose_prompt_id) + + current_user.record_vote("test_vote", @p, rand(2)) + end + + end + + desc "Should only need to be run once" + task(:generate_all_possible_prompts => :environment) do + inserts = [] + Question.find(:all).each do |q| + choices = q.choices + if q.prompts.size > choices.size**2 - choices.size + print "ERROR: #{q.id}\n" + next + elsif q.prompts.size == choices.size**2 - choices.size + print "#{q.id} has enough prompts, skipping...\n" + next + else + print "#{q.id} should add #{(choices.size ** 2 - choices.size) - q.prompts.size}\n" + + end + timestring = Time.now.to_s(:db) #isn't rails awesome? + promptscount=0 + the_prompts = Prompt.find(:all, :select => 'id, left_choice_id, right_choice_id', :conditions => {:question_id => q.id}) + + the_prompts_hash = {} + the_prompts.each do |p| + the_prompts_hash["#{p.left_choice_id},#{p.right_choice_id}"] = 1 + end + + choices.each do |l| + choices.each do |r| + if l.id == r.id + next + else + #p = the_prompts.find{|o| o.left_choice_id == l.id && o.right_choice_id == r.id} + keystring = "#{l.id},#{r.id}" + p = the_prompts_hash[keystring] + if p.nil? + print "." + inserts.push("(NULL, #{q.id}, NULL, #{l.id}, '#{timestring}', '#{timestring}', NULL, 0, #{r.id}, NULL, NULL)") + promptscount+=1 + end + + end + + end + end + + print "Added #{promptscount} to #{q.id}\n" + + Question.update_counters(q.id, :prompts_count => promptscount) + + end + + sql = "INSERT INTO `prompts` (`algorithm_id`, `question_id`, `voter_id`, `left_choice_id`, `created_at`, `updated_at`, `tracking`, `votes_count`, `right_choice_id`, `active`, `randomkey`) VALUES #{inserts.join(', ')}" + + unless inserts.empty? + ActiveRecord::Base.connection.execute(sql) + end + + end + + + desc "Dump votes of a question by left vs right id" + task(:make_csv => :environment) do + + q = Question.find(120) + + the_prompts = q.prompts_hash_by_choice_ids + + #hash_of_choice_ids_from_left_to_right_to_votes + the_hash = {} + the_prompts.each do |key, p| + left_id, right_id = key.split(", ") + if not the_hash.has_key?(left_id) + the_hash[left_id] = {} + the_hash[left_id][left_id] = 0 + end + + the_hash[left_id][right_id] = p.votes.size + end + + the_hash.sort.each do |xval, row| + rowarray = [] + row.sort.each do |yval, cell| + rowarray << cell + end + puts rowarray.join(", ") + end + end + + desc "Description here" task(:question_vote_consistency => :environment) do questions = Question.find(:all) -- libgit2 0.21.2