Complex Queries + Basic Statistics in Rails

I inherited a rails codebase that was written about 5 years ago. The codebase is a web application for a nonprofit that does leadership training and assessments. Training participants perform a self-assessment and invite peers to evaluate their leadership. Each training participant receives a report that shows their self score in relation to peer scores, and other leaders who have taken the same assessment. The nonprofit’s database contains more than 80,000 rows of assessment scores. Not exactly “big data”, but not exactly small either.

Each assessment report contains roughly 20 – 30 assessment questions. Each question shows the self-score, peer scores, average peer score, and the quartile (compared against all previous assessments).

For each question, I looked up the peer evaluation scores for the participant:

def numeric_answers_for_q(question_id)
  Answer.joins(:evaluation, :question).where(:evaluations => {self_eval: false,
    :questions => {id: question_id, answer_type: 'numeric'}).
    where.not(numeric_response: 0).
    where.not(numeric_response: nil).

In this case, I found all numeric answers, (there are also text answers), for completed peer evaluations for the given question and participant. Zero and nil answers are considered as not applicable, so we ignore these results.

Once I receive an the array of peer answers, I create a histogram with the array. The results of the histogram are later displayed.

def histogram_for_q(answers)
  histogram = {|i| 0}
  answers.each do |a|
    histogram[a] += 1 unless a.nil? ||
  return histogram

I also need the mean score.

def mean_score_for_q(answers)

If I only needed the mean score, I could’ve replace ‘pluck(:numeric_response)’ with ‘average(:numeric_response)’ in the numeric_answers_for_q method. I do this when I need the mean scores from previous assessments for comparison.

def self.peer_assessment_scores(question_id, participant_id)
    avgs_by_participant = Answer.joins(:evaluation, :question).where(:evaluations => {self_eval: false,
                                                     :questions => {answer_type: 'numeric', id: question_id}).
                                                     where.not(:evaluations => { participant_id: participant_id }).
                                                     where.not(numeric_response: 0).
                                                     where.not(numeric_response: nil).
                                                     average(:numeric_response) {|k,v| v.to_f }

This last method I found the pretty helpful. Being able to find grouped averages based on complex conditions.

Code reviews are welcomed. Please post suggestions in the comments.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

About Hadiyah

Practicing loving God, neighbors, and myself daily. Leveraging venture capital to advance racial equity at HBCUvc.