I have built two methods in exams_helper.rb to use in views:
<% @topic_questions.each do |topic_question| %>
<tr>
<td><%= topic_question.topic.name %></td>
<td><%= correct_questions(@exam_result.exam_id, topic_question.topic_id) %></td>
<td><%= number_to_percentage(ratio(@exam_result.exam_id, topic_question.topic_id), precision: 0) %></td>
</tr>
<% end %>
Method to calculate the number of correct question of topic:
def correct_questions(exam_id, topic_id)
total = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id).count
correct = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id, correct: true).count
correct.to_s + '/' + total.to_s
end
Method to calculate percentage of correctness
def ratio(exam_id, topic_id)
total = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id).count
correct = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id, correct: true).count
ratio = (correct.to_f/total).round(2)*100
if ratio.nan?
ratio = 0
else
ratio
end
end
These code is repeated:
total = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id).count
correct = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id, correct: true).count
How can I write these method better?
In my opinion, these methods should rely in your Model as their purpose is to compute data from Database. Also, by writing these methods in the Model layer, you can avoid duplication in controllers, views or view helpers.
View helpers should only be used for ‘view-logic’ methods, that do not make much sense outside of the view context.
correct_questions and ratio seem to be closely related to the ExamResult object, we could imagine the following implementation:
Memoization is a form of “caching” to avoid recomputing the same result many times. You can find many articles about it. Here is a good one : http://www.railway.at/articles/2008/09/20/a-guide-to-memoization/
Finally, you would have the following code in your view. The helper is not really necessary anymore, but you can still write a helper method to construct the “correct/total” part, taking an ExamResult instance – @exam_result – as a parameter.