burningpony/phd_checker

View on GitHub
app/models/user.rb

Summary

Maintainability
A
3 hrs
Test Coverage
class User < ActiveRecord::Base
  require 'csv'
  has_many :responses, dependent: :destroy
  has_many :rounds, dependent: :destroy
  def self.aggregate_analysis(users)
    return if users.empty?
    CSV.generate do |csv|
      csv << User.new.analyze.keys
      users.sort_by(&:group).each do |user|
        csv << user.analyze.values
      end
    end
  end

  def analyze
    {
      id: id,
      group: group,
      data_id: participant_id,
      treatment: rounds.pluck(:name).compact.first.try(:to_i),
      option: rounds.pluck(:option).compact.first.try(:to_i),
      total_time_taken: rounds.sum(:time_elapsed_in_seconds),
      total_edited: responses.count,
      total_correct: responses.where(correct: true).count,
      total_earned: total_payment,
      cumulative_impact: User.counter_part_impact(responses.where(correct: true).count, responses.where(correct: false).count),
      finished_early: rounds.where(completed_in_time: true).present?.to_i,
      created_at: created_at,
      round_1_edit: responses.where(round_number: 1).count,
      round_1_correct: responses.where(round_number: 1, correct: true).count,
      round_2_edit: responses.where(round_number: 2).count,
      round_2_correct: responses.where(round_number: 2, correct: true).count,
      round_3_edit: responses.where(round_number: 3).count,
      round_3_correct: responses.where(round_number: 3, correct: true).count,
      round_4_edit: responses.where(round_number: 4).count,
      round_4_correct: responses.where(round_number: 4, correct: true).count,
      calc_time_to_complete_round_1: rounds.where(round_number: 1).first.try(:time_elapsed_in_seconds),
      calc_time_to_complete_round_2: rounds.where(round_number: 2).first.try(:time_elapsed_in_seconds),
      calc_time_to_complete_round_3: rounds.where(round_number: 3).first.try(:time_elapsed_in_seconds),
      calc_time_to_complete_round_4: rounds.where(round_number: 4).first.try(:time_elapsed_in_seconds),
      round_1_earned: rounds.where(round_number: 1).pluck(:round_payment).first,
      round_2_earned: rounds.where(round_number: 2).pluck(:round_payment).first,
      round_3_earned: rounds.where(round_number: 3).pluck(:round_payment).first,
      round_4_earned: rounds.where(round_number: 4).pluck(:round_payment).first,
      counter_part_impact_1: round_impact(1),
      counter_part_impact_2: round_impact(2),
      counter_part_impact_3: round_impact(3),
      counter_part_impact_4: round_impact(4),
      finish_round_1_early: rounds.where(round_number: 1).pluck(:completed_in_time).first.to_i,
      finish_round_2_early: rounds.where(round_number: 2).pluck(:completed_in_time).first.to_i,
      finish_round_3_early: rounds.where(round_number: 3).pluck(:completed_in_time).first.to_i,
      finish_round_4_early: rounds.where(round_number: 4).pluck(:completed_in_time).first.to_i,
      average_time_to_edit_correct_1: responses.where(round_number: 1, correct: true).average(:total_time_to_edit),
      average_time_to_edit_correct_2: responses.where(round_number: 2, correct: true).average(:total_time_to_edit),
      average_time_to_edit_correct_3: responses.where(round_number: 3, correct: true).average(:total_time_to_edit),
      average_time_to_edit_correct_4: responses.where(round_number: 4, correct: true).average(:total_time_to_edit),
      average_time_to_edit_incorrect_1: responses.where(round_number: 1, correct: false).average(:total_time_to_edit),
      average_time_to_edit_incorrect_2: responses.where(round_number: 2, correct: false).average(:total_time_to_edit),
      average_time_to_edit_incorrect_3: responses.where(round_number: 3, correct: false).average(:total_time_to_edit),
      average_time_to_edit_incorrect_4: responses.where(round_number: 4, correct: false).average(:total_time_to_edit),
      average_time_to_edit_1: responses.where(round_number: 1).average(:total_time_to_edit),
      average_time_to_edit_2: responses.where(round_number: 2).average(:total_time_to_edit),
      average_time_to_edit_3: responses.where(round_number: 3).average(:total_time_to_edit),
      average_time_to_edit_4: responses.where(round_number: 4).average(:total_time_to_edit),
      average_time_to_edit_incorrect: responses.where(correct: false).average(:total_time_to_edit),
      average_time_to_edit_correct: responses.where(correct: true).average(:total_time_to_edit),
      average_time_to_edit: responses.average(:total_time_to_edit),
      total_actions: responses.pluck("sum(json_array_length(actions)) as total_actions")[0],
      job: job,
    }.merge(analyzed_available_payments)
  end

  def analyzed_available_payments
    @analyzed_available_payments ||= {}
    Job.all.each do |job|
      Payment.all.each do |payment|
        if available_payments.present? && available_payments.is_a?(Hash) && available_payments[job]
          available = available_payments[job].include?(payment) ? 1 : 0
        else
          available = nil
        end
        @analyzed_available_payments["job_#{job}_option_#{payment}".to_sym] = available
      end
    end
    @analyzed_available_payments
  end

  def round_impact(round)
    User.counter_part_impact(responses.where(round_number: round, correct: true).count, responses.where(round_number: round, correct: false).count)
  end

  def self.counter_part_impact(number_correct, number_wrong)
    (0.15 * number_correct.to_f - 0.05 * number_wrong.to_f).round(5)
  end
end