Tracking the Results of a Rails-Powered Survey

Setup of my Rails Survey App

After officially entering the world of rails a couple weeks ago at the Flatiron School, I decided to start a personal rails project to solidify my skills. I chose to put the survey porition of my undergrad these online. The survey asks respondents questions about their perception of a learning experience. The data is ideally displayed in a series of radar graphs and bar graphs. This blog post focuses on how I collect survey responses in the correct format.

Luckily for me, the Flatiron Dean made a Quiz App a public repo during class. I forked this repo, which already had 5 models: Quiz, Question, Choice, Answer, and User. My task now was to calculate the results.

Collect the Rails App Survey Results

For the purpose of this post, the survey has 48 questions, which is broken down into 6 sets of 8 questions. The method I made to solve this problem was three-tiered:

  1. Collect survey answers in sets of 8
  2. Correctly compare a user’s answer with all possible choices
  3. Based on the user’s answer, assign that person a score

See the code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Quiz < ActiveRecord::Base
  has_many :questions
  has_many :results

  def results_as_set_of_8(user, range)
    score = 0
     self.questions[range].each_with_index do |q, qi|
       q.choices.each_with_index do |c, ci|
         if c.id == user.answers[range.first + qi].choice_id
           score += ci +5 - (2*ci)
         end
       end
     end
     return score/8.0
  end
end
  1. Sets of 8 uses range

    This method takes range as a parameter, so that I can specify which set of 8 questions. The range also gets used to compare the question with its corresponding answer.

  2. Correctly compare a user’s answers with all possible choices

    I used the each_with_index method on the range of questions to find two pieces of information:

    which question id corresponds with the first answer id (start at range.first) as the .each enumerable changes which question is being handled, correspond that change with the appropriate answer id (by proceeding upwards with qi)

    To do this, I specified which answer with:

    ruby user.answers[range.first + qi]

    Once this synchronization between question and a user’s answer is made, I checked all of a question’s choices to see if their id matches the answer’s choice id, of which it has only one.

  3. Based on the user’s answer, assign that person a score

    Another challenge was associating number values with the choice object, which has the single String attribute of :content. Becuase the survey arranges choice.content from values of 5 to 1, such as, “Strongly Agree, Agree, Neither Agree nor Disagree, Disagree, Strongly Disagree,” I ended up making a simple formula to assign the right score:

    ruby score += ci +5 - (2*ci)

    Everytime the user’s answer’s choice id matches a quesiton’s choice id, then based on its position in a.choices, the above algebraic expression calculates the right score. Furthermore, this method finds the score sum because at the end, it finds the average score with score/8.0.

Coding Takeaways

  1. Make it work

    Things might have been easier for me if I gave choices a value attribute. Tracking the value of a choice would make they survey app more flexible, such as if i wanted to randomize the order in which choices appear.

    But rather than going backwards over my code, I moved forward first, trusting my ability to refactor in the future.

  2. Use debugger

    Initially, I missed how to correctly associate user.answers with quiz.quesitons. My method worked for the first set of 8 questions, but not for sets after that. By looking at the progression of the code through debugger, I visibly saw where my method failed becuase the if c.id statement was never triggered.

By focusing on making it work, and looking at the code with detail and granularity, I quickly made my app functional. Though next time, I’ll add a value attribute to the choice model and make my life easier.