CSC/ECE 517 Spring 2022 - E2243. Refactor student teams functionality

From Expertiza_Wiki
Jump to navigation Jump to search

This page contains information about Expertiza Issue E2243. Refactor student teams functionality which was a project in CSC517 Spring 2022.

Please see below for a description of the design of the project.

Background

The Expertiza project is software to create reusable learning objects through peer review. It also supports team projects, and the submission of almost any document type, including URLs and wiki pages.

Users & Participants: Everyone who took the CSC517 OODD class at NC State is a user in Expertiza, and instructors can add users as participants in an assignment so that they can access it to contribute, make changes and submit their work to be graded.

Almost all of the works within Assignments is done by participants, not users. All the tables use participant_id to track contributions to assignments, except teams_users. In the documentation, it can be noted that the team_users table references users instead of participants. This anomaly in the teams_users relation causes problems with how student teams are rendered in the UI, and it doesn’t mix well with the new functionality that was recently introduced.

As given in the specifications for the project, the name of the table "teams_users" should be changed to "teams_participants". The participant_id field should be added to the model, and references that use user_id should also incorporate participant_id.

Given Requirements

Changing the schema

  • We need to rename the table table teams_users to teams_participants.
  • Create a column that would be called “participant_id”, which will be a foreign key that references the participants table.
  • Create a migration that fetches the assignment_id for each tuple from the teams table. We would find the participant with the help of the assignment_id we just got from the teams table and the user_id that is already present in the current table, and store its “id” in the participant_id column we created in the last step.

Refactoring the teams rendering (/views/student_teams/view.html.erb)

The logic in the team's view (where participants can see their team members) that iterates and fetches information of all the team members and displays them would be refactored so that it matches our new design. The view is quite bloated and has lots of functionalities written on it. We’ll be making partials and placing those functionality in their specific partials.

Other Changes

Update logic for all the crud functionalities in teams_users controller (wherever applicable). Rename the teams_users_controller to teams_participants_controller (and all its references)

Schema Changes

In teams_users table, we can add a new column participant_id which is a foreign key from participants table and remove the column user_id. We plan to remove the user_id column only after data migration since the user_id field is used predominantly in several other controllers in a variety of ways, and as such its removal must be done carefully.

The participant_id field in the the teams_users relation is computed as follows:

  • Finding Assignment ID By Team ID

The teams_users table contains team_id, user_id and duty_id but not the participant_id. Since the same user_id can be associated with multiple participant_ids (since the same user can participate in multiple assignments and gets a unique participant_id in each assignment they take part in), we need to get the user_ids in the assignment for which we need the particular user's participant_id. For this reason, we need to first find the assignment_id.

  • Finding Participant ID By Assignment ID and User ID

With the assignment_id retrieved, we can find the list of participant_ids that participated in the assignment, and using the user_id, get the participant_id which is saved in the participants table.

ER diagram for updated schema

Data Migration

Analysis

user_id exists as a foreign key in 2 relations - Participants and teams_users. Although they crrespond to same attribute, user_id alone cannot be used to find corresponding Participants because same user_id can exist for multiple Participants - due to Expertiza's design wherein for every assignment, every user is added to participant's table. Therefore Participant ID can be mapped to (assignment_id, user_id) pair.

Proposed Implementation

Finding Assignment ID using Team ID

Each team is associated with an assignment. The parent_id in teams table corresponds to assignment_id. Therefore, team_id in teams_users table can be used to get the Team object and in turn fetch the Assignment ID (present as parent_id in the teams table)

# Code snippet to fetch assignment_id based on team_id
assignment_id = Team.find(team_id).select(:parent_id)

Finding Participant ID By Assignment ID and User ID

The Assignment object can be fetched using the assignment ID. Each assignment contains a list of participants. The Participant object contains a user_id attribute. Since, a user can have only one entry in the Participants table for an assignment, we can use user_id to find the user's participant_id from this list.

# Code snippet to fetch participant_id based on assignment_id and user_id
participant_id = Assignment.find(assignment_id).participants.find_by(:user_id user_id)

Approach One

The above mentioned code snippets can be used for each tuple in the teams_users table.

# Brute Force Code Snippet
TeamsUser.all.each do |teamsUser|
    assignment_id = Team.find(teamsUser.team_id).select(:parent_id)
    participant_id = Assignment.find(assignment_id).participants.find_by(:user_id teamsUser.user_id)
    teamsUser.update_attribute(:participant_id, participant_id)
end

Approach Two

In the brute force approach (Approach One), database calls are made multiple times inside the loop. Moving the database calls out of the loop will give us a more efficient solution.

Steps:

  1. Load all the TeamUser objects.
  2. Load all the Team objects for all the team_ids in TeamUser object
  3. Create a map with team_id as key and assignment_id as value. The resultant map usage: map[team_id] = assignment_id
  4. Load all the Assignment objects for all the assignment_ids from the map in the previous step. Also eager fetch participants along with the assignments.
  5. Create a nested map with assignment_id and user_id as key and participant_id as value. The resultant map usage: map[assignment_id][user_id] = participant_id
  6. For all TeamUser objects, find the participant_id from the maps generated from the previous steps and update the participant_id attribute.

View Changes

The existing views in relation to this functionality would not need to undergo signification refactoring, since we are only adding a new field and removing any of the existing ones. That being said, we will be adding new partials to achieve the similar views using the participant_id field instead of the user_id field in the partials for future changes to the application as mentioned in the specifications.

Effects of code changes in the Expertiza Application

While the renaming of the table to teams_participants has rippling effects throughout the program since multiple files contain calls to this class, It must be noted that not much else needs to change apart from the class name. In most cases, only the class name would be changed since we are primarily adding a new field(participant_id) and not removing any existing fields.

In most use cases noted in the application for the teams_users class, the main use cases seen are computed the team_id from the user_id and assignment_id or manipulations on the users in a teams_user object - adding and removing a team members from a team, for instance.

The changes we plan to make here will not cause a need for changes in other parts of the application apart from the replacement of the class name to teams_participants.

Impacted Files

  • teams_users_controller.rb (expertiza/app/controller/teams_user_controller.rb)

We will be adding code here to compute the participant_id using the methodologies described above.

  • teams_users.rb (expertiza/app/models/teams_user.rb)

The model will be updated (as can be seen in the ER diagram above) to have the participant_id added.

  • teams_users(expertiza/app/views/teams_users)