CSC/ECE 517 Fall 2016/E1640. Refactor response.rb and response helper.rb

From Expertiza_Wiki
Jump to navigation Jump to search

Introduction to Expertiza

Expertiza is a web application developed using Ruby on Rails for online assignment assessment. It is an open source project and its code base is maintained in the Git repository. Expertiza authorizes the instructor to create new assignments as well as modify the existing ones. Students can team up with other students in Expertiza to work on various projects and assignments. Students can also review other students' work, thus enabling peer learning. After a particular response is recorded, the rubric gets displayed in graphical form under Your Scores tab. The submitted work can be seen in Your Work tab and the feedback given can be seen in Others' Work. The teammates for a particular project can be seen in Your team tab.


Overview

Response Model

Response.rb is a class that manages the response to all rubrics in Expertiza. The review form, quiz attempt, teammate review, review for others' work, filling a survey are all treated as responses. Method display_as_html handles the front-end for displaying a rubric.

Helper module

Response_helper.rb

It contains two kinds of methods:

1) Methods related to the display of questionnaires.

2) Methods to open a rubric on selecting a particular section name.

This contains a method that rearranges the questions based on the frequency of answers to the questions.


Project Requirements

In response.rb:

1) The class contains code that checks the rubric type (ReviewResponseMap, MetareviewResponseMap, FeedbackResponseMap, TeammateReviewResponseMap). These classes are sub-classes of ResponseMap. Rather than checking the map type, the code should send a message to the ResponseMap, and the code for specific types of ResponseMaps should be implemented in the subclasses of ResponseMap.

2) Code for calculating scores seems to be incorrect, as it should multiply per-question scores by the weight for each question. It seems to ignore weighting.

3) Most of the code for sending e-mails should be moved to app/mailers.

4) Remove the comment in lines 25–27 about TeamResponseMap; it is no longer relevant to the current version.


In response_helper.rb:

1)The rearrange_questions method was written before we added sequence numbers to questions. At the very least, it needs to be modified so that questions above the threshold are kept in sequence. Ideally, it would be extended to allow the person who creates the rubric to specify whether each question could be moved or not, and then rearrange only the questions that are allowed to be moved, and add a column of check boxes to the Rubrics tab for assignment creation, saying whether questions on a particular rubric can be rearranged or not.


Issues addressed

In response.rb

1) The functionality for email notification was initially cluttered in a single class Response. In the current version, this functionality is been divided into sub-classes depending on the response type. This has facilitated improved modularity and segregation of functionality into different classes.

2) In the current version of the code, the total score is calculated by considering the weights for each question.

3) The code for email notification is in the mailer module in the current version and the syn_message function is used for sending synchronous email messages after a response is entered.

4) The irrelevant lines from TeamResponseMap are removed.


In response_helper.rb

1) The response_helper.rb is removed in the current version since it is dead code and not referenced anywhere in the code.


Code Modifications

The email notification functionality was initially in Response.rb and was shifted to the sub-classes as below:

Before Refactoring :
Model: Response.rb

def email()
if response_map.type == "ReviewResponseMap"
  defn[:body][:type] = "Author Feedback"
  AssignmentTeam.find(response_map.reviewee_id).users.each do |user|
    defn[:body][:obj_name] = if assignment.has_topics?
                               SignUpTopic.find(SignedUpTeam.topic_id(assignment.id, user.id)).topic_name
                             else
                               assignment.name
                             end
    defn[:body][:first_name] = User.find(user.id).fullname
    defn[:to] = User.find(user.id).email
    Mailer.sync_message(defn).deliver_now
  end
if response_map.type == "MetareviewResponseMap"
  defn[:body][:type] = "Metareview"
  reviewee_user = Participant.find(response_map.reviewee_id)
  signup_topic_id = SignedUpTeam.topic_id(assignment.id, response_map.contributor.teams_users.first.user_id)

  defn[:body][:obj_name] = SignUpTopic.find(signup_topic_id).topic_name
  defn[:body][:first_name] = User.find(reviewee_user.user_id).fullname
  defn[:to] = User.find(reviewee_user.user_id).email
  Mailer.sync_message(defn).deliver
end
if response_map.type == "FeedbackResponseMap" # This is authors' feedback from UI
  defn[:body][:type] = "Review Feedback"
  # reviewee is a response, reviewer is a participant
  # we need to track back to find the original reviewer on whose work the author comments
  response_id_for_original_feedback = response_map.reviewed_object_id
  response_for_original_feedback = Response.find response_id_for_original_feedback
  response_map_for_original_feedback = ResponseMap.find response_for_original_feedback.map_id
  original_reviewer_participant_id = response_map_for_original_feedback.reviewer_id

  participant = AssignmentParticipant.find(original_reviewer_participant_id)
  topic_id = SignedUpTeam.topic_id(participant.parent_id, participant.user_id)
  defn[:body][:obj_name] = if topic_id.nil?
                             assignment.name
                           else
                             SignUpTopic.find(topic_id).topic_name
                           end

  user = User.find(participant.user_id)

  defn[:to] = user.email
  defn[:body][:first_name] = user.fullname
  Mailer.sync_message(defn).deliver
end
if response_map.type == "TeammateReviewResponseMap"
  defn[:body][:type] = "Teammate Review"
  participant = AssignmentParticipant.find(response_map.reviewee_id)
  topic_id = SignedUpTeam.topic_id(participant.parent_id, participant.user_id)
  defn[:body][:obj_name] = SignUpTopic.find(topic_id).topic_name rescue nil
  user = User.find(participant.user_id)
  defn[:body][:first_name] = user.fullname
  defn[:to] = user.email
  Mailer.sync_message(defn).deliver
end
end

After Refactoring :
Model changed: Response.rb, ReviewResponseMap.rb, MetareviewResponseMap.rb, FeedbackResponseMap.rb, TeammateReviewResponseMap.rb
Function added: email
In ReviewResponseMap

def email(defn,assignment,participant)
    defn[:body][:type] = "Author Feedback"
    AssignmentTeam.find(reviewee_id).users.each do |user|
      defn[:body][:obj_name] = if assignment.has_topics?
                                 SignUpTopic.find(SignedUpTeam.topic_id(assignment.id, user.id)).topic_name
                               else
                                 assignment.name
                               end
      defn[:body][:first_name] = User.find(user.id).fullname
      defn[:to] = User.find(user.id).email
      Mailer.sync_message(defn).deliver_now
    end
  end


In MetareviewResponseMap

def email(defn,participant,assignment)
    defn[:body][:type] = "Metareview"
    reviewee_user = Participant.find(reviewee_id)
    signup_topic_id = SignedUpTeam.topic_id(assignment.id, contributor.teams_users.first.user_id)
    defn[:body][:obj_name] = SignUpTopic.find(signup_topic_id).topic_name
    defn[:body][:first_name] = User.find(reviewee_user.user_id).fullname
    defn[:to] = User.find(reviewee_user.user_id).email
    Mailer.sync_message(defn).deliver
  end


In FeedbackResponseMap

def email(defn,assignment,participant)
    defn[:body][:type] = "Review Feedback"
# reviewee is a response, reviewer is a participant
# we need to track back to find the original reviewer on whose work the author comments
    response_id_for_original_feedback = reviewed_object_id
    response_for_original_feedback = Response.find response_id_for_original_feedback
    response_map_for_original_feedback = ResponseMap.find response_for_original_feedback.map_id
    original_reviewer_participant_id = response_map_for_original_feedback.reviewer_id
    participant = AssignmentParticipant.find(original_reviewer_participant_id)
    topic_id = SignedUpTeam.topic_id(participant.parent_id, participant.user_id)
    defn[:body][:obj_name] = if topic_id.nil?
                               assignment.name
                             else
                               SignUpTopic.find(topic_id).topic_name
                             end
    user = User.find(participant.user_id)
    defn[:to] = user.email
    defn[:body][:first_name] = user.fullname
    Mailer.sync_message(defn).deliver
  end
  end


In TeammateReviewResponseMap

def email(defn,assignment,participant)
    defn[:body][:type] = "Teammate Review"
    participant = AssignmentParticipant.find(reviewee_id)
    topic_id = SignedUpTeam.topic_id(participant.parent_id, participant.user_id)
    defn[:body][:obj_name] = SignUpTopic.find(topic_id).topic_name rescue nil
    user = User.find(participant.user_id)
    defn[:body][:first_name] = user.fullname
    defn[:to] = user.email
    Mailer.sync_message(defn).deliver
  end

Testing

New refactoring has been tested and verified using existing Rspec tests. Manual testing has been done for the functionalities which does not have any existing Rspec tests.

References

  1. Expertiza on Github
  2. Current Expertiza website
  3. Expertiza project Wiki Documentation
  4. Ruby on Rails Guides