User:Psnakhwa
This wiki page is for the description of changes made under E1633 OSS assignment for Fall 2016, CSC/ECE 517. The objective of the project is to refactor different question types from quiz feature.
Introduction
About Expertiza
Expertiza is a web application where students can submit assignments and quizzes and also peer-review learning objects (articles, code, web sites, etc). Expertiza achieves this using a web application with a straightforward user interface developed using Ruby on Rails. The Expertiza project is supported by the National Science Foundation.
Motivation
This project provides an opportunity for students with likeminded interests to collaborate and work as a team to enhance the existing source code of expertiza so as to improve functionality, remove bugs and implement altogether new features. This in turn provides students with a chance to showcase their skills in applying various concepts and techniques such as RSpec testing, code refactoring, CRUD design, testing strategies and other object oriented practices amongst many others.
Drawbacks of the System
- Currently, Expertiza has a quizzing feature which allow student authors to create quiz questions and “test" the peer-reviewers. The idea behind this is, if a reviewer can answer the quiz questions which were created by the author correctly, we assume that the reviewer has read the artifact carefully enough and thereby we trust the peer-review.
- Quiz questionnaire is one sub type of questionnaire, so it should follow the design of other type of questionnaires.
- However, there are quite a few inconsistencies lodged in the quizzing feature.
- The number one reason that we plan to refactor the quizzing feature is that its design is not consistent with the current questions and questionnaires.
- Repetition of source code can be observed in quite a few areas of the system, which can be avoided.
- The system does not adhere to the Rails principle of Convention over Configuration and Ruby naming conventions are violated in certain segments of the code.
Changes made to the System
- The logic of necessary components was moved to the model methods. The views were correspondingly changed to invoke the required model methods.
- The different methods defined were edit, view_completed_question, complete and view_question_text.
- The above methods generated the specified HTML content for the specified question types, namely : MultipleChoiceCheckbox, MultipleChoiceRadio, TrueFalse.
Functionalities of the new methods
- When the user chooses the ‘edit’ option in a quiz, the edit method is called. Based on our modification of the view, the edit method is now invoked from /view/questionnaires/_quiz_questionnaire.html.erb
- When a user tries to take a quiz by pressing on ‘begin quiz’ in the UI, the ‘complete' method is invoked by the given view : view/student_quizzes/take_quiz
- When a user chooses the option ‘view quiz’ or ‘view quiz questions' in the system, the view_question_text method is called which renders the view : view/questionnaires/view.html.erb
- When the user decides to choose option ‘view’ on a completed quiz, the view_ completed_question method is called on view/student_quizzes/finished_quiz
Refactoring view_question_text
The view_question_text method is called when the author of the quiz or the instructor views the quiz. The method is responsible for generating the HTML to display the question along with each of its choices. The correct choice(s) should be bolded. Prior to refactoring, this functionality was located in app/views/student_quizzes/review_questions.html.erb:
<h1 xmlns="http://www.w3.org/1999/html"> Listing of All Quiz Questions for <%= Assignment.find(@assignment_id).name %> </h1> <table> <%@quiz_questionnaires.each do |questionnaire|%> <%author_team = Team.find(questionnaire.instructor_id)%> <h2> Quiz create by <%=author_team.name%></h2> <%topic_id = SignedUpTeam.topic_id_by_team_id(author_team.id)%> <%if topic_id.nil?%> <%topic_name=nil%> <%else%> <%topic_name = SignUpTopic.find(topic_id).topic_name%> <h4> Topic: <%=topic_name%></h4> <%end%> <% response_maps = QuizResponseMap.where(reviewed_object_id:questionnaire.id) %> <% if !response_maps.empty? %> <table border="2"> <tr> <th> quiz taker </th> <% response_maps.each do |response_map| %> <% reviewer_paritcipant_id = response_map.reviewer_id%> <% reviewer_user_id = Participant.find(reviewer_paritcipant_id).user_id%> <td> <%=User.find(reviewer_user_id).fullname%></td> <%end%> </tr> <% quiz_scores = [] %> <tr> <th> quiz score </th> <% response_maps.each do |response_map| %> <% quiz_score = response_map.quiz_score%> <%quiz_scores.push(quiz_score) if !quiz_score.eql?('N/A')%> <td> <%=quiz_score%></td> <%end%> </tr> </table> <br> <% if quiz_scores.size!= 0 %> Average score for quiz takers: <%= (quiz_scores.sum / quiz_scores.size).round(2) %> <br><br> <% end %> <% end %> <%questions = questionnaire.questions%> <% questions.each do |question| %> <%= question.view_question_text%> <% end %><hr> <% end %> </table>
This logic has been moved to app/models/quiz_question.rb, so now the view simply needs to call the method:
def view_question_text html = "<b>" + self.txt + '</b><br />' html += "Question Type: " + self.type + '<br />' if self.quiz_question_choices self.quiz_question_choices.each do |choices| html += if choices.iscorrect? " - <b>" + choices.txt + "</b><br /> " else " - " + choices.txt + "<br /> " end end html += '<br />' end html.html_safe end
Refactoring edit
The edit method is called when the author creates or edits a quiz. It makes every element of the quiz editable. Prior to refactoring, the HTML was in app/views/questionnaires/_quiz_questionnaire.html.erb:
<%= error_messages_for 'questionnaire' %> <table> <tr> <td valign="top"><label for="questionnaire_name">Name:</label> <%= text_field 'questionnaire', 'name' %> <%= hidden_field 'questionnaire', 'id' %> <%= hidden_field 'questionnaire', 'type' %> </td> </tr> </table> <br/> <% if @questionnaire.type == 'QuizQuestionnaire' %> <!--handle a questionnaire differently if it is a quiz--> <table id="questions_table"> <% if $disp_flag != 1 %> <tr> <td align=left width=300>Questions:</td> <% if @questionnaire.type != 'QuizQuestionnaire' %><td align=left>weight</td><%end%> </tr> <% end %> <% for @question in @questionnaire.questions %> <% questionnum=@question.id %> <tr> <% if $disp_flag != 1 %> <td > <%= text_area "question[]", 'txt', :cols=>100 %></td> <% end %> <% @quiz_question_choices = QuizQuestionChoice.where(question_id: @question.id) %> </tr> <% i=1 %> <% for @quiz_question_choice in @quiz_question_choices %> <tr> <td> <% if @question.type=="MultipleChoiceCheckbox" %> <%= hidden_field_tag("quiz_question_choices[#{questionnum}][MultipleChoiceCheckbox][#{i}][iscorrect]",'0') %> <%= check_box_tag("quiz_question_choices[#{questionnum}][MultipleChoiceCheckbox][#{i}][iscorrect]",'1', @quiz_question_choice.iscorrect) %> <%= text_field_tag "quiz_question_choices[#{questionnum}][MultipleChoiceCheckbox][#{i}][txt]", @quiz_question_choice.txt, :size=>40 %> <% end %> <%if @question.type=="MultipleChoiceRadio" %> <%= radio_button_tag("quiz_question_choices[#{questionnum}][MultipleChoiceRadio][correctindex]", "#{i}", @quiz_question_choice.iscorrect)%> <%= text_field_tag "quiz_question_choices[#{questionnum}][MultipleChoiceRadio][#{i}][txt]", @quiz_question_choice.txt, :size=>40 %> <% end %> <%if @question.type=="TrueFalse" %> <% if @quiz_question_choice.txt=="True"%> <%= radio_button_tag("quiz_question_choices[#{questionnum}][TrueFalse][1][iscorrect]", 'True', @quiz_question_choice.iscorrect) %> True <%end%> <% if @quiz_question_choice.txt=="False"%> <%= radio_button_tag("quiz_question_choices[#{questionnum}][TrueFalse][1][iscorrect]", 'False', @quiz_question_choice.iscorrect) %> False <%end%> <% end %> </td> </tr> <% i+=1 %> <%end %> <% end %> </table> <% end %> <BR/>
After refactoring, the same file looked like:
<%= error_messages_for 'questionnaire' %> <table> <tr> <td valign="top"><label for="questionnaire_name">Name:</label> <%= text_field 'questionnaire', 'name' %> <%= hidden_field 'questionnaire', 'id' %> <%= hidden_field 'questionnaire', 'type' %> </td> </tr> </table> <br/> <% if @questionnaire.type == 'QuizQuestionnaire' %> <!--handle a questionnaire differently if it is a quiz--> <table id="questions_table"> <% if $disp_flag != 1 %> <tr> <td align=left width=300>Questions:</td> <% if @questionnaire.type != 'QuizQuestionnaire' %><td align=left>weight</td><%end%> </tr> <% end %> <% for @question in @questionnaire.questions %> <% var=1 %> <%= @question.edit(var) %> <% end %> </table> <% end %> <br/>
Refactoring complete
Logic is written in multiple_choice_checkbox model for multiple choice checkbox question type. Similarly, same process is followed for remaining question types. To begin a quiz, complete is called from the model.
@question = self html = "" html += label_tag("#{question.id}", question.txt) +"
" quiz_question_choices = QuizQuestionChoice.where(question_id: @question.id) quiz_question_choices.each do |choice| if answer=="view" html += check_box_tag ("#{question.id}[]", "#{choice.txt}", choice.iscorrect) html += label_tag("#{choice.txt}", choice.txt) + "
" end if answer=="take" html += check_box_tag ("#{question.id}[]", "#{choice.txt}") html += label_tag("#{choice.txt}", choice.txt) + "
" end html.html_safe end end
Refactoring view_completed_question
The logic for viewing completed question and their answers is written in app/views/student_quizzes/finished_quiz.html.erb and the code was refactored so as to call the view_completed_question method declared in quiz class as shown below.
<h2>Answers</h2> <b>Quiz score: <%= @quiz_score %>%</b> <% @assignment = Assignment.find(@participant.parent_id)%> <%= render :partial => 'submitted_content/main', :locals => {:participant => @participant, :stage => ""} %> <br> <% i = 1 %> <% @questions.each do |question| %> <b>Question <%= i %>: </b><%= label_tag "#{question.id}", question.txt %> <br> <% question_type = question.type %> <% if question_type.eql? 'MultipleChoiceRadio' %> <% QuizQuestionChoice.where(question_id: question.id).each do |answer| %> <% if(answer.iscorrect) %> <b><%= p answer.txt %></b> -- Correct <br> <%else%> <%= p answer.txt %><br> <% end %> <% end %> <br> <%user_answer=Answer.where(response_id: @response.id, question_id: question.id).first%> Your answer is: <b><%= user_answer.comments %></b> <%if user_answer.answer==1%> <img src="/assets/Check-icon.png"/> <%else%> <img src="/assets/delete_icon.png"/> <%end%> <br><br> <% elsif question_type.eql? 'MultipleChoiceCheckbox' %> <br> <% QuizQuestionChoice.where(question_id: question.id).each do |answer| %> <% if(answer.iscorrect) %> <b><%= p answer.txt %></b> -- Correct <br> <%else%> <% end %> <% end %><br> Your answer is: <% user_answers= Answer.where(response_id: @response.id, question_id: question.id)%> <%if user_answers.first.answer==1%> <img src="/assets/Check-icon.png"/> <%else%> <img src="/assets/delete_icon.png"/> <%end%> <br/> <% user_answers.each do |answer| %> <b><%= answer.comments %></b><br> <% end %> <br> <% elsif(question_type == 'TrueFalse') %> Correct Answer is: <b><%=QuizQuestionChoice.where(question_id: question.id,iscorrect: 1).first.txt%></b><br/> <%user_answer=Answer.where(response_id: @response.id, question_id: question.id).first%> Your answer is: <b><%= user_answer.comments %></b> <%if user_answer.answer==1%> <img src="/assets/Check-icon.png"/> <%else%> <img src="/assets/delete_icon.png"/> <%end%> <br><br> <% end %><hr> <% i += 1 %> <% end %> <%= link_to "Back", student_quizzes_path(:id => @response_map.reviewer_id) %>
Testing the System
If you are using the link in the Expertiza submission, you do not need a password. We made this change to facilitate testing. The committed code does not make any change for authenticating users.
Since this project involved code refactoring, no new functionality was added. But here are tests for each method to verify they are working correctly.
view_question_text
- Login as a student.
- Select a quiz assignment.
- Select "Your Work"
- If you haven't created a quiz yet, go ahead and create one by clicking the "Create Quiz" link.
- Select "View quiz".
- You should see each question, followed by the choices. The correct choice(s) will be bolded.
edit
- Login as a student.
- Select a Quiz Assignment.
- Select "Your Work"
- If you haven't created a quiz yet, go ahead and create one by clicking the "Create Quiz" link.
- Select "Edit quiz".
- You should see each question, followed by the choices, each in an editable text field. The correct choice(s) will be checked.
complete
- Login as a student.
- Select an assignment that has quizzing enabled (e.g. Quiz Assignment).
- Select "Your Work"
- If you haven't created a quiz yet, go ahead and create one by clicking the "Create Quiz" link.
- Select "Take Quizzes".
- Click 'Begin'.
- You should see each question, followed by the choices. You can record your answers for each questions and then click 'submit'. Your answers will be saved.
view_completed_question
- Login as a student.
- Select an assignment that has quizzing enabled (e.g. Quiz Assignment).
- Select "Your Work"
- If you haven't created/taken a quiz yet, go ahead and create one by clicking the "Create Quiz" link and take the quiz.
- Find a finished quiz and click on 'View'.
- You should see each question, followed by the choices. The correct choice(s) will be bolded and your recorded answer will be shown.